/** * SSRF guard for audit targets. * * Two layers: * 1. `isPrivateOrReservedHost(hostname)` — fast, synchronous string check. * Catches literal private IPs ("10.0.0.5"), loopback names ("localhost"), * link-local suffixes (".local"), and internal/metadata hostnames. * 2. `validateTargetHost(hostname)` — async. Resolves the hostname via DNS * and rejects if the resulting address (v4 or v6) falls into a private / * reserved / link-local / multicast range. Mitigates DNS rebinding where * a public hostname returns 127.0.0.1. * * Usage: * const hostname = new URL(userSuppliedUrl).hostname; * await validateTargetHost(hostname); // throws SSRFError on blocked targets * * Library consumers should call this BEFORE enqueuing a crawl. The audit * engine itself wraps its own fetches with this check when `guardSsrf` is * enabled in AuditOptions, but defense-in-depth at the API boundary is the * primary mitigation. */ export declare class SSRFError extends Error { readonly hostname: string; readonly reason: string; constructor(hostname: string, reason: string); } /** * Thrown when a hostname legitimately fails DNS resolution (NXDOMAIN / SERVFAIL * / no A / AAAA records). Distinct from `SSRFError`: resolution failure * is a "try again later / fix your typo" condition, not an attack. Callers * in SaaS contexts should not log these as security events. */ export declare class DnsResolutionError extends Error { readonly hostname: string; constructor(hostname: string); } /** * IPv4 range predicate — true if the address is private / reserved / * link-local / loopback / multicast / broadcast / CGNAT. Expects a valid * dotted-quad; caller must ensure that (e.g. via `net.isIP`). */ export declare function isPrivateIPv4(addr: string): boolean; /** * IPv6 range predicate — true for loopback, ULA, link-local, unspecified, * multicast, and IPv4-mapped addresses (after unwrapping to the v4 check). */ export declare function isPrivateIPv6(addr: string): boolean; /** * Decode an integer-packed (`2130706433` = `127.0.0.1`) or hex-encoded * (`0x7f000001`) hostname into dotted-quad form. Returns `null` if the * input isn't a numeric hostname. Needed because some fetch stacks accept * these encodings and resolve them to private IPs, bypassing a naive * string-only dotted-quad check. */ export declare function decodeNumericIPv4(hostname: string): string | null; /** * Synchronous string-only check. Rejects: * - literal private / reserved IP addresses (dotted-quad OR numeric/hex encoding) * - exact blocked hostnames (localhost, 0, etc.) * - suffix-blocked hostnames (.local, .internal, .arpa, ...) * * Returns `null` if the host is acceptable, or a human-readable reason * string if it should be blocked. */ export declare function isPrivateOrReservedHost(hostname: string): string | null; export interface ValidateTargetHostOptions { /** Override the DNS resolver — useful for tests or custom resolvers. */ resolver?: { resolve4: (hostname: string) => Promise; resolve6: (hostname: string) => Promise; }; } /** * Full SSRF check: the string check above PLUS a DNS lookup to guarantee the * resolved address isn't in a private range. Throws `SSRFError` on failure. * * Time-of-check-vs-time-of-use: an attacker-controlled DNS server can return * a public IP on first lookup and a private IP on the subsequent fetch ("DNS * rebinding"). Mitigations: cache the resolved IP and dial to THAT IP (host * header preserved), or use a resolver that refuses re-resolution within a * TTL window. This function validates; it does not pin. For the audit * engine's own fetches, the pinning layer is layered on top via `safeFetch`. */ export declare function validateTargetHost(hostname: string, options?: ValidateTargetHostOptions): Promise; /** * Convenience check for "is this URL pointing at localhost or a private * network?". Used by the CLI to auto-apply a conservative crawl preset when * a developer runs `pseolint http://localhost:3000` — a cache-cold local * server can amplify every fetch into a thundering herd of DB queries. * * Returns false for anything that isn't a parseable URL with a hostname * (paths, `file://`, empty strings). Delegates the actual decision to * `isPrivateOrReservedHost` so the two stay in sync. */ export declare function isLocalhostUrl(url: string): boolean; //# sourceMappingURL=ssrf-guard.d.ts.map