# Pathrule Pattern: SSRF and Egress Security (1.0.0)
# ::pathrule:package:ssrf-egress-security

### [RULE] Parse once and allow only required URL schemes and forms  (path: /src/network/fetch)
<!-- scope: folder | priority: high | strict -->

Do not secure outbound requests with substring checks or regular expressions over the raw URL. Parse with one well-tested library, reject parse ambiguity and embedded credentials, normalize the hostname deliberately, and allow only the schemes and ports the feature needs. Most remote-content features should accept HTTPS only.

- Reject non-network schemes such as file, data, gopher, ftp, and runtime-specific handlers.
- Handle IPv4, IPv6, integer, hexadecimal, octal, encoded, trailing-dot, Unicode, and mixed-case host representations through canonical parsing and tests.
- Prefer a destination allowlist for known integrations and a narrow deny policy only when arbitrary public hosts are a true product requirement.
- Keep the validated URL object through connection setup instead of reparsing or concatenating later.

Verification: Run a corpus of alternative localhost, private-address, credential, port, and parser-confusion forms; confirm every equivalent forbidden destination is rejected.

---

### [RULE] Validate every resolved address before connection  (path: /src/network/fetch)
<!-- scope: folder | priority: high | strict -->

A hostname string that looks public can resolve to loopback, private, link-local, multicast, reserved, documentation, or cloud metadata space. Resolve the canonical host through a controlled resolver, inspect every IPv4 and IPv6 result, and reject the request if any candidate violates policy or if the connector might choose a different unvalidated answer.

- Apply explicit IP range classification rather than a short list of familiar private prefixes.
- Bind or otherwise verify the chosen connection address to reduce DNS rebinding between validation and connect.
- Restrict resolver search paths and internal DNS exposure for untrusted arbitrary-host features.
- Treat resolution failure, mixed public and private answers, and unsupported address forms as denial.

Verification: Test direct addresses, mixed A and AAAA answers, rebinding behavior, internal names, metadata ranges, and resolution races; confirm the socket reaches only an approved address.

---

### [RULE] Redirects repeat the complete destination check  (path: /src/network/fetch)
<!-- scope: folder | priority: high | strict -->

A permitted public URL can redirect to an internal address, another scheme, an unexpected port, or a long redirect chain. Disable automatic redirect following whenever the feature does not need it. When redirects are required, treat each Location as a new untrusted URL and repeat parsing, scheme, port, hostname, DNS, and IP checks before connection.

- Set a small redirect limit and detect loops using canonical destinations.
- Do not forward authorization headers, cookies, client certificates, or signed request data across origins.
- Apply the same timeout, response-size, content-type, and egress policy on every hop.
- Record safe destination categories and rejection reasons without logging secrets embedded in input.

Verification: Redirect a public host through multiple encodings to loopback, metadata, another scheme, and a second origin; confirm no forbidden hop receives a request or credential.

---

### [RULE] The fetcher runs behind enforced network and response limits  (path: /infra/egress)
<!-- scope: folder | priority: high | strict -->

Application validation can regress, so the runtime that performs untrusted fetches must also lack network reach to sensitive internal services and metadata endpoints. Place the capability in an isolated worker or workload with the narrowest outbound policy, no ambient cloud credentials, no internal service discovery, and a dedicated identity.

- Enforce connect, read, and total deadlines plus maximum redirects, headers, compressed bytes, decompressed bytes, and concurrent requests.
- Stream into bounded storage and stop before parsing unexpected or oversized content.
- Resolve and connect through the approved proxy or egress gateway so policy cannot be bypassed by a custom client.
- Expose only the minimal normalized result to callers, never raw internal headers, socket errors, or timing detail.

Verification: Bypass application checks in a test environment and attempt internal, metadata, oversized, slow, compressed-bomb, and high-concurrency requests; confirm infrastructure contains each case.

---

### [MEMORY] Outbound fetch is a capability, not a reusable convenience helper  (path: /src/integrations)

A general fetch(url, options) helper spreads SSRF review across every caller and lets later code add methods, headers, bodies, redirects, or destinations the original feature never required. Expose purpose-specific operations such as fetchPublicImage, deliverWebhookToVerifiedEndpoint, or readApprovedFeed with policy fixed inside the boundary.

Give each capability its own allowed methods, schemes, ports, destination model, credentials, request body, redirect behavior, content types, size limits, and normalized result. Keep vendor API clients separate from arbitrary public-content fetchers. Review any new option as an expansion of network authority. See /src/network/fetch for canonical validation and /infra/egress for the independent containment layer.

---

### [RULE] Untrusted fetch capability has an accountable usage budget  (path: /src/integrations)
<!-- scope: folder | priority: medium | strict -->

Even a destination-safe fetcher can become a scanning, bandwidth, storage, or denial-of-service primitive. Require an authenticated caller or narrowly scoped workload identity, authorize the named fetch capability, and charge each request to a tenant, user, job, or integration budget before network work begins. Anonymous features need a separately constrained public abuse policy.

- Limit request rate, concurrent work, total bytes, unique destinations, retries, and retained output by accountable subject.
- Prevent one redirect chain, batch request, or retry loop from escaping the original budget.
- Expose safe rejection categories and correlation ids while hiding target resolution and internal network detail.
- Alert on repeated forbidden destinations, limit exhaustion, unusual host diversity, and policy bypass attempts.

Verification: Distribute abusive requests across redirects, batches, retries, tenants, and worker restarts; confirm consumption stays bounded and attributable.

---

### [SKILL] test-ssrf-boundary  (path: /src/network/fetch)

---
name: test-ssrf-boundary
description: Test an outbound URL-fetching boundary against SSRF and resource-exhaustion cases.
---

# Test SSRF Boundary

1. Inventory every caller, accepted input form, HTTP method, header, credential, scheme, port, redirect behavior, parser, resolver, proxy, and runtime network path.
2. Run canonicalization cases for IPv4, IPv6, encoded and alternate numeric forms, Unicode names, credentials, fragments, ports, and non-HTTP schemes.
3. Serve controlled DNS answers that are private, mixed, changed between lookup and connect, or redirected through several hops.
4. Attempt metadata and internal services, slow responses, excessive headers, large and highly compressed bodies, wrong content types, redirect loops, and concurrency pressure.
5. Confirm both application policy and infrastructure deny safely, record the actual connected address, and retain regression fixtures for every bypass found.

A passing test proves the network destination, not merely the input string, stayed inside policy.
