/** * SSRF guard for the `watch` tool — applied to both the watched URL and any * webhook notification URL. Pre-merge review on A1 (the stub PR) flagged * that the schema allowed unguarded URLs of either field; B3 closes that * gap before any real fetch fires. * * Reject: * - non-http(s) schemes (file://, ftp://, gopher://, data:, javascript:, ...) * - loopback (localhost, 127.0.0.0/8, ::1) * - all-zeros (0.0.0.0) * - RFC 1918 private ranges (10/8, 172.16/12, 192.168/16) * - link-local (169.254/16, fe80::/10) * - IPv6 unique-local (fc00::/7) and IPv6 loopback * * Accept ordinary public hostnames + their IPs. DNS rebinding is out of * scope — we never actually resolve here. This guard is the gate before a * job is persisted; a follow-up tier could re-check at fetch time, but for * the v0.3.0 surface the input-side guard is the documented contract. */ /** * Stable machine-readable reason codes for a rejection. The REST error adapter * keys the HTTP status on these codes — never on the human-readable `reason` * prose (which embeds variable host values and can be reworded freely). A test * pins the adapter's key set against this object so wording drift can never * silently break status mapping. */ export declare const SSRF_CODES: { readonly INVALID_URL: "ssrf_invalid_url"; readonly BAD_PROTOCOL: "ssrf_bad_protocol"; readonly PRIVATE_TARGET: "ssrf_private_target"; readonly METADATA: "ssrf_metadata"; }; export type SsrfCode = (typeof SSRF_CODES)[keyof typeof SSRF_CODES]; export interface SsrfRejection { ok: false; code: SsrfCode; reason: string; hint: string; } export interface SsrfAllowed { ok: true; url: URL; } export type SsrfResult = SsrfAllowed | SsrfRejection; /** * Guard a single URL string. Returns `{ ok:true, url }` on accept, or * `{ ok:false, reason, hint }` on reject. Callers should pipe the reject * payload straight into a StageError envelope. */ export declare function guardUrl(raw: string, fieldLabel: string): SsrfResult; /** * Fetch/crawl-friendly URL guard. Same as `guardUrl` but EXEMPTS loopback * (127.0.0.0/8, ::1) and link-local IPv6 (fe80::/10) so local dev servers * (localhost:3000) keep working — the `fetch` tool explicitly documents this. * * Still blocks: * - non-http(s) schemes (file://, ftp://, gopher://, data:, javascript:, ...) * - 0.0.0.0/8 (unspecified / commonly routes to local) * - RFC 1918 private ranges (10/8, 172.16/12, 192.168/16) * - CGN (100.64/10) — ISP-grade NAT, often used by ISPs to share IPv4 * - link-local IPv4 (169.254/16) — covers AWS/GCP/Azure metadata endpoints * - IPv6 unique-local (fc00::/7) * - IPv6 IPv4-mapped / IPv4-compatible forms of any of the above * * When `allowPrivate` is true (e.g. WIGOLO_FETCH_ALLOW_PRIVATE=1), private * LAN ranges are permitted so home users can still fetch NAS / IoT / dev * boxes on 192.168.x.x. Metadata IPs (169.254/16) remain blocked in all * modes because they're never a legitimate target for a generic fetch. */ export declare function guardFetchUrl(raw: string, fieldLabel: string, opts?: { allowPrivate?: boolean; }): SsrfResult; //# sourceMappingURL=ssrf.d.ts.map