@peac/protocol 0.10.7 → 0.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/crypto-utils.d.ts +9 -0
- package/dist/crypto-utils.d.ts.map +1 -0
- package/dist/crypto-utils.js +21 -0
- package/dist/crypto-utils.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/pointer-fetch.d.ts +86 -0
- package/dist/pointer-fetch.d.ts.map +1 -0
- package/dist/pointer-fetch.js +305 -0
- package/dist/pointer-fetch.js.map +1 -0
- package/dist/ssrf-safe-fetch.d.ts +205 -0
- package/dist/ssrf-safe-fetch.d.ts.map +1 -0
- package/dist/ssrf-safe-fetch.js +671 -0
- package/dist/ssrf-safe-fetch.js.map +1 -0
- package/dist/transport-profiles.d.ts +115 -0
- package/dist/transport-profiles.d.ts.map +1 -0
- package/dist/transport-profiles.js +424 -0
- package/dist/transport-profiles.js.map +1 -0
- package/dist/verification-report.d.ts +135 -0
- package/dist/verification-report.d.ts.map +1 -0
- package/dist/verification-report.js +322 -0
- package/dist/verification-report.js.map +1 -0
- package/dist/verifier-core.d.ts +62 -0
- package/dist/verifier-core.d.ts.map +1 -0
- package/dist/verifier-core.js +578 -0
- package/dist/verifier-core.js.map +1 -0
- package/dist/verifier-types.d.ts +328 -0
- package/dist/verifier-types.d.ts.map +1 -0
- package/dist/verifier-types.js +161 -0
- package/dist/verifier-types.js.map +1 -0
- package/package.json +17 -5
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSRF-safe fetch utility for PEAC verifiers
|
|
3
|
+
*
|
|
4
|
+
* Implements SSRF protection per VERIFIER-SECURITY-MODEL.md:
|
|
5
|
+
* - HTTPS only
|
|
6
|
+
* - Block private IP ranges (RFC 1918)
|
|
7
|
+
* - Block link-local addresses
|
|
8
|
+
* - Block loopback addresses
|
|
9
|
+
* - Redirect limits and scheme downgrade protection
|
|
10
|
+
*
|
|
11
|
+
* ## Security Model: Best-Effort Protection
|
|
12
|
+
*
|
|
13
|
+
* **IMPORTANT**: SSRF protection is BEST-EFFORT, not a guarantee. The level of
|
|
14
|
+
* protection depends on the runtime environment's capabilities. In environments
|
|
15
|
+
* without DNS pre-resolution (browsers, edge workers), protection is limited to
|
|
16
|
+
* URL scheme validation and response limits. Defense-in-depth: combine with
|
|
17
|
+
* network-level controls (firewalls, egress filtering) in production.
|
|
18
|
+
*
|
|
19
|
+
* ## Hard Invariants (ALWAYS Enforced)
|
|
20
|
+
*
|
|
21
|
+
* These protections are enforced in ALL runtimes:
|
|
22
|
+
*
|
|
23
|
+
* | Invariant | Enforcement |
|
|
24
|
+
* |-----------|-------------|
|
|
25
|
+
* | HTTPS only | URL scheme validation before fetch |
|
|
26
|
+
* | No redirects (pointer fetch) | `redirect: 'manual'` + policy check |
|
|
27
|
+
* | Response size cap | Streaming with byte counter, abort on limit |
|
|
28
|
+
* | Timeout | AbortController with configurable timeout |
|
|
29
|
+
* | No scheme downgrade | Redirect target scheme validation |
|
|
30
|
+
*
|
|
31
|
+
* ## Runtime-Dependent Protections
|
|
32
|
+
*
|
|
33
|
+
* These protections require DNS pre-resolution capability:
|
|
34
|
+
*
|
|
35
|
+
* | Protection | Requires |
|
|
36
|
+
* |------------|----------|
|
|
37
|
+
* | Private IP blocking (RFC 1918) | DNS pre-resolution |
|
|
38
|
+
* | Loopback blocking (127.0.0.0/8) | DNS pre-resolution |
|
|
39
|
+
* | Link-local blocking (169.254.0.0/16) | DNS pre-resolution |
|
|
40
|
+
*
|
|
41
|
+
* ## Runtime Capability Model
|
|
42
|
+
*
|
|
43
|
+
* SSRF protection capabilities vary by runtime environment:
|
|
44
|
+
*
|
|
45
|
+
* | Runtime | DNS Pre-Resolution | IP Blocking | Notes |
|
|
46
|
+
* |-------------------|-------------------|-------------|-------|
|
|
47
|
+
* | Node.js | YES | YES | Full protection via dns module |
|
|
48
|
+
* | Browser | NO | NO | Relies on server-side validation |
|
|
49
|
+
* | Cloudflare Workers| NO | NO | No DNS access, relies on CF network |
|
|
50
|
+
* | Deno | NO | NO | dns module not available by default |
|
|
51
|
+
* | Bun | YES | YES | Compatible with Node.js dns module |
|
|
52
|
+
*
|
|
53
|
+
* Use `getSSRFCapabilities()` to detect runtime capabilities.
|
|
54
|
+
*
|
|
55
|
+
* @packageDocumentation
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* Runtime environment where SSRF protection is running
|
|
59
|
+
*/
|
|
60
|
+
export type SSRFRuntime = 'node' | 'bun' | 'deno' | 'browser' | 'cloudflare-workers' | 'edge-generic' | 'unknown';
|
|
61
|
+
/**
|
|
62
|
+
* SSRF protection capabilities available in the current runtime
|
|
63
|
+
*
|
|
64
|
+
* These capabilities determine what security measures can be applied:
|
|
65
|
+
* - `dnsPreResolution`: Can resolve hostnames to IPs before connecting
|
|
66
|
+
* - `ipBlocking`: Can inspect and block connections based on resolved IPs
|
|
67
|
+
* - `networkIsolation`: Runtime provides network-level isolation (e.g., CF Workers)
|
|
68
|
+
*
|
|
69
|
+
* When `dnsPreResolution` is false, SSRF protection is limited to:
|
|
70
|
+
* - URL scheme validation (HTTPS only)
|
|
71
|
+
* - Hostname pattern matching (if configured)
|
|
72
|
+
* - Response size limits
|
|
73
|
+
* - Timeout enforcement
|
|
74
|
+
*
|
|
75
|
+
* This is a defense-in-depth model: even without DNS pre-resolution,
|
|
76
|
+
* multiple layers of protection remain active.
|
|
77
|
+
*/
|
|
78
|
+
export interface SSRFCapabilities {
|
|
79
|
+
/** Detected runtime environment */
|
|
80
|
+
runtime: SSRFRuntime;
|
|
81
|
+
/** Can resolve DNS before making HTTP connection */
|
|
82
|
+
dnsPreResolution: boolean;
|
|
83
|
+
/** Can block connections based on resolved IP addresses */
|
|
84
|
+
ipBlocking: boolean;
|
|
85
|
+
/** Runtime provides network-level isolation */
|
|
86
|
+
networkIsolation: boolean;
|
|
87
|
+
/** Human-readable description of protection level */
|
|
88
|
+
protectionLevel: 'full' | 'partial' | 'minimal';
|
|
89
|
+
/** Advisory notes for operators */
|
|
90
|
+
notes: string[];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Detect SSRF protection capabilities for the current runtime
|
|
94
|
+
*
|
|
95
|
+
* This function performs runtime detection and returns a capability object
|
|
96
|
+
* that describes what SSRF protections are available.
|
|
97
|
+
*
|
|
98
|
+
* @returns SSRF capabilities for the current runtime
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const caps = getSSRFCapabilities();
|
|
103
|
+
* if (!caps.dnsPreResolution) {
|
|
104
|
+
* console.warn('Running without DNS pre-resolution; SSRF protection is limited');
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare function getSSRFCapabilities(): SSRFCapabilities;
|
|
109
|
+
/**
|
|
110
|
+
* Reset cached capabilities (for testing)
|
|
111
|
+
* @internal
|
|
112
|
+
*/
|
|
113
|
+
export declare function resetSSRFCapabilitiesCache(): void;
|
|
114
|
+
/**
|
|
115
|
+
* SSRF fetch options
|
|
116
|
+
*/
|
|
117
|
+
export interface SSRFFetchOptions {
|
|
118
|
+
/** Timeout in milliseconds (default: VERIFIER_LIMITS.fetchTimeoutMs) */
|
|
119
|
+
timeoutMs?: number;
|
|
120
|
+
/** Maximum response size in bytes (default: VERIFIER_LIMITS.maxResponseBytes) */
|
|
121
|
+
maxBytes?: number;
|
|
122
|
+
/** Maximum redirects to follow (default: 0 for SSRF safety) */
|
|
123
|
+
maxRedirects?: number;
|
|
124
|
+
/** Allow redirects (default: VERIFIER_NETWORK.allowRedirects) */
|
|
125
|
+
allowRedirects?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Allow cross-origin redirects (default: true for CDN compatibility).
|
|
128
|
+
* When true, redirects to different origins are allowed if the target passes SSRF checks.
|
|
129
|
+
* When false, redirects must stay within the same origin.
|
|
130
|
+
*/
|
|
131
|
+
allowCrossOriginRedirects?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* How to handle DNS resolution failures (default: 'block' for fail-closed security).
|
|
134
|
+
* - 'block': Treat DNS failure as blocked (fail-closed, recommended)
|
|
135
|
+
* - 'fail': Return network_error and allow caller to decide
|
|
136
|
+
*/
|
|
137
|
+
dnsFailureBehavior?: 'block' | 'fail';
|
|
138
|
+
/** Custom headers to include */
|
|
139
|
+
headers?: Record<string, string>;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* SSRF fetch result
|
|
143
|
+
*/
|
|
144
|
+
export interface SSRFFetchResult {
|
|
145
|
+
/** Whether the fetch succeeded */
|
|
146
|
+
ok: true;
|
|
147
|
+
/** Response status code */
|
|
148
|
+
status: number;
|
|
149
|
+
/** Response body as string */
|
|
150
|
+
body: string;
|
|
151
|
+
/**
|
|
152
|
+
* Raw response bytes for digest computation.
|
|
153
|
+
* Use this for computing digests to avoid encoding round-trip issues.
|
|
154
|
+
*/
|
|
155
|
+
rawBytes: Uint8Array;
|
|
156
|
+
/** Response content type */
|
|
157
|
+
contentType?: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* SSRF fetch error
|
|
161
|
+
*/
|
|
162
|
+
export interface SSRFFetchError {
|
|
163
|
+
/** Fetch failed */
|
|
164
|
+
ok: false;
|
|
165
|
+
/** Error reason code */
|
|
166
|
+
reason: 'invalid_url' | 'not_https' | 'private_ip' | 'loopback' | 'link_local' | 'dns_failure' | 'too_many_redirects' | 'scheme_downgrade' | 'cross_origin_redirect' | 'timeout' | 'response_too_large' | 'jwks_too_many_keys' | 'network_error';
|
|
167
|
+
/** Human-readable error message */
|
|
168
|
+
message: string;
|
|
169
|
+
/** Blocked URL (if applicable) */
|
|
170
|
+
blockedUrl?: string;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check if an IP address is private/blocked
|
|
174
|
+
*/
|
|
175
|
+
export declare function isBlockedIP(ip: string): {
|
|
176
|
+
blocked: true;
|
|
177
|
+
reason: 'private_ip' | 'loopback' | 'link_local';
|
|
178
|
+
} | {
|
|
179
|
+
blocked: false;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Perform an SSRF-safe fetch
|
|
183
|
+
*
|
|
184
|
+
* This function implements the SSRF protection algorithm from VERIFIER-SECURITY-MODEL.md:
|
|
185
|
+
* 1. Parse URL; reject if not https://
|
|
186
|
+
* 2. Resolve hostname to IP(s)
|
|
187
|
+
* 3. For each IP: reject if private, link-local, or loopback
|
|
188
|
+
* 4. Perform fetch with timeout
|
|
189
|
+
* 5. On redirect: increment counter, reject if > max, apply checks to redirect URL
|
|
190
|
+
* 6. Validate response size
|
|
191
|
+
*
|
|
192
|
+
* @param url - URL to fetch (must be https://)
|
|
193
|
+
* @param options - Fetch options
|
|
194
|
+
* @returns Fetch result or error
|
|
195
|
+
*/
|
|
196
|
+
export declare function ssrfSafeFetch(url: string, options?: SSRFFetchOptions): Promise<SSRFFetchResult | SSRFFetchError>;
|
|
197
|
+
/**
|
|
198
|
+
* Convenience function to fetch JWKS with SSRF protection
|
|
199
|
+
*/
|
|
200
|
+
export declare function fetchJWKSSafe(jwksUrl: string, options?: Omit<SSRFFetchOptions, 'maxBytes'>): Promise<SSRFFetchResult | SSRFFetchError>;
|
|
201
|
+
/**
|
|
202
|
+
* Convenience function to fetch pointer target with SSRF protection
|
|
203
|
+
*/
|
|
204
|
+
export declare function fetchPointerSafe(pointerUrl: string, options?: Omit<SSRFFetchOptions, 'maxBytes'>): Promise<SSRFFetchResult | SSRFFetchError>;
|
|
205
|
+
//# sourceMappingURL=ssrf-safe-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf-safe-fetch.d.ts","sourceRoot":"","sources":["../src/ssrf-safe-fetch.ts"],"names":[],"mappings":"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"}
|