harden(egress): SSRF defenses for url type, always-block cloud metadata, manifest lint#8
Open
jaschadub wants to merge 1 commit into
Open
harden(egress): SSRF defenses for url type, always-block cloud metadata, manifest lint#8jaschadub wants to merge 1 commit into
jaschadub wants to merge 1 commit into
Conversation
…nifest lint Extends the scope_target hardening across the egress surface: - url validator: apply scope_target's host hygiene to curl/wget-style fetchers (the prime SSRF vector) — canonical-IP-only host, reject obfuscated IP-literal hosts (0x7f000001 / 2130706433), reject punycode hosts, and apply the egress IP policy to literal-IP hosts. - always-block link-local / cloud metadata (169.254.0.0/16, fe80::/10, incl. v4-mapped) for scope_target AND url, regardless of block_internal — IMDS credential theft has maximal blast radius and ~zero legitimate egress use. - manifest lint: a manifest whose command invokes a known egress binary (curl/wget/nmap/nc/...) must set block_internal on its scope_target/url args, or it is refused at load — turns a silent unsafe default into a CI failure. - set block_internal=true on the nmap_scan and curl_fetch examples (+ the nmap test fixture) to satisfy the new lint. Shared enforce_ip_policy()/always_blocked_ip_reason() helpers. +4 tests (metadata-always, url hardening, egress lint pass/fail); 91 pass, clippy clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to the
scope_targethardening. Extends SSRF defenses across the whole egress surface, scoped by the rule "if the command connects to the target, default-deny internal."1.
urlvalidator hardened (the priority gap)curl/wget-style fetchers are the prime SSRF vector, andvalidate_urlpreviously had no internal-block or IP-canonicalization — it passedhttp://169.254.169.254/latest/meta-data/andhttp://0x7f000001/. Now the URL host gets the same hygiene asscope_target: canonical-IP-only host, reject obfuscated IP-literal hosts, reject punycode hosts, and apply the egress IP policy to literal-IP hosts.2. Always-block cloud metadata / link-local
169.254.0.0/16andfe80::/10(incl. v4-mapped) are now blocked forscope_targetandurlregardless ofblock_internal. IMDS credential theft has maximal blast radius and ~zero legitimate egress use, so it shouldn't depend on a flag. Loopback/private remain gated byblock_internal.3. Manifest lint (enforce, don't rely on memory)
A manifest whose command invokes a known egress binary (
curl,wget,nmap,nc,masscan,ssh, …) must setblock_internalon itsscope_target/urlargs, or it is refused at load. Turns a silent unsafe default into a load-time failure.4. Scope the flags
block_internal = trueon thenmap_scanandcurl_fetchexamples (they connect to the target).whois/digstay off — they take the target as a lookup key, not a connection endpoint.Limitation (documented)
String-level IP checks catch literal internal IPs but not DNS rebinding (a public hostname resolving to
169.254.169.254at connect time). The durable fix is resolve-then-check at connect time in the executor / an egress proxy;block_internalis defense-in-depth.Testing
+4 tests (metadata-always, url host hardening, egress-lint pass/fail). 91 pass;
cargo clippy --all-targetsclean. Sharedenforce_ip_policy()/always_blocked_ip_reason()helpers.