fix(modules): exempt webdriver transport from SSRF filter 🐛#324
fix(modules): exempt webdriver transport from SSRF filter 🐛#324dohernandez wants to merge 1 commit into
Conversation
In docker topologies the webdriver hostname resolves to an RFC1918 address, so routing Render's request to the operator-configured webdriver_host through the filtering client crash-looped every docker deploy with ADDRESS_FORBIDDEN. The contract-controlled target URL is already validated by check_url; the transport hop now uses the unfiltered client, like the LLM backends. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
GenVM PR actionsTick a box to run it (the box unticks itself when handled). Actions only run while the PR has the
Full GenVM CI runs only when |
Summary
Field blocker on v0.3.0-rc6 docker deploys: the web module's
Render()sends its request to the operator-configuredwebdriver_hostthrough the SSRF-filtered client. In docker topologies the webdriver hostname resolves to an RFC1918 address, soFilteringResolverdrops every resolved address and every docker deploy of the node's boot self-test crash-loops with a non-fatal-but-boot-fatalADDRESS_FORBIDDEN. Host deploys withwebdriver_host: http://127.0.0.1:4444were unaffected only because IP-literal transport URLs never enter the resolver.The fix is one line in
genvm-web-default.lua:Render()'s webdriver call now passesunfiltered = true, using the opt-out plumbing thatRequest()already uses foralways_allow_hosts. Rationale:webdriver_hostis operator-configured infrastructure — the same trust class as the LLM backends, which already go through the plain client (filter_dns=false) — while the contract-controlled input (the render target URL) is validated byweb.check_urlbefore the transport request is built. The filtered client remains in place for all contract-controlled fetches.Also audited per the incident report:
split_urluses theurlcrate, which normalizes all literal-IP spellings (dotted/decimal/hex) beforecheck_url's TLD check lexically rejects them, and the filtered client's redirect policy rejects IP-literal redirect hops (test_redirect_to_private_ip_is_rejected).Tests
New
modules/implementation/tests/web_render_webdriver.rs, exercising the realgenvm-web-default.luawith afilter_dns=truectx (as the real web module builds it) andwebdriver_hostonlocalhost.direct(public DNS resolving only to loopback — the incident topology in miniature):render_reaches_loopback_only_webdriver_host— fails without the fix with the field incident's exact signature (causes: ["ADDRESS_FORBIDDEN"]on the/renderURL), passes with it.filtered_default_client_still_blocks_loopback— the same ctx still blocks a plain filtered request to the same host, so the pass above is attributable to the opt-out, not a loosened filter.Existing SSRF filter tests (
request_localhost.rs, 4) pass.🤖 Generated with Claude Code