Skip to content

fix(core): restrict web viewport URLs to public http/https#64

Merged
hyperb1iss merged 2 commits into
mainfrom
codex/fix-webviewport-local-file-exfiltration
May 19, 2026
Merged

fix(core): restrict web viewport URLs to public http/https#64
hyperb1iss merged 2 commits into
mainfrom
codex/fix-webviewport-local-file-exfiltration

Conversation

@hyperb1iss
Copy link
Copy Markdown
Owner

@hyperb1iss hyperb1iss commented May 19, 2026

Motivation

  • The Web Viewport renderer accepted arbitrary URLs (including file:// and private/localhost IPs) and published full rendered frames to a preview channel, enabling a local-file/SSRF exfiltration chain on default unauthenticated loopback installs.

Description

  • Add validate_web_url() to enforce only http/https schemes and reject localhost/.local hostnames and loopback/private/link-local IP literals before passing a URL to Servo.
  • Call the validator from both the initial load path and the debounced/subsequent load path to block disallowed targets before any Servo load occurs.
  • Add is_private_or_loopback_ip() helper used by the policy, update the url control help text to remove file:// guidance, and adjust URL-normalization-related unit tests.
  • Include small unit tests around the new IP classification helper and update existing module tests to reflect the tightened URL policy.

Testing

  • Ran cargo test -p hypercolor-core web_viewport (compilation progressed in this environment but the full test run did not complete during the session). (partial)
  • Ran cargo fmt --check -p hypercolor-core which reported formatting diffs (failed due to crate-wide formatting differences). (failed)
  • Ran rustfmt on the modified file to fix formatting (succeeded). (succeeded)

Codex Task

Summary by CodeRabbit

Release Notes

  • New Features
    • Webpage URL validation now restricts loading to HTTP/HTTPS schemes with valid public hosts. Localhost, .local domains, and private/loopback IP addresses cannot be loaded.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Warning

Rate limit exceeded

@hyperb1iss has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 57 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d7446bd0-8f52-4860-ac3e-5e27607a4350

📥 Commits

Reviewing files that changed from the base of the PR and between d7ca558 and 685893a.

📒 Files selected for processing (1)
  • crates/hypercolor-core/src/effect/builtin/web_viewport.rs
📝 Walkthrough

Walkthrough

The PR adds URL validation to the web viewport renderer to restrict loading to absolute HTTP/HTTPS URLs with valid, non-private hosts. A new validate_web_url helper enforces scheme requirements, requires a host, rejects localhost and .local domains, and blocks private/loopback/link-local IP addresses. Validation is called before each URL load operation, and tests are updated to cover IP classification and HTTP-scheme preservation.

Changes

Web Viewport URL Validation

Layer / File(s) Summary
Validation helper functions and imports
crates/hypercolor-core/src/effect/builtin/web_viewport.rs
anyhow error utilities are imported to support validation. validate_web_url parses URLs and enforces http/https absolute schemes, requires a host, rejects localhost and .local hostnames, and delegates IP-level checks to is_private_or_loopback_ip to reject loopback, private, and link-local addresses.
Apply validation at URL load entry points and documentation
crates/hypercolor-core/src/effect/builtin/web_viewport.rs
validate_web_url(&url)? is called during runtime URL load before session.load_url and during initial session URL setup. The URL control description is updated to document that only HTTP/HTTPS URLs are allowed.
Test imports, URL scheme verification, and IP classification
crates/hypercolor-core/src/effect/builtin/web_viewport.rs
Test module imports are extended to include validation helpers and IP address types. The existing URL normalization test is adjusted to expect an http://-schemed URL. A new test verifies that is_private_or_loopback_ip correctly classifies loopback, private, unique-local IPv6, and non-private public IPv4 addresses.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A rabbit hops past localhost gates,
And blocks the private IP fates,
Only HTTPS may pass us by,
For Servo's web to safely fly!
Validation keeps the URLs pure,
And serves the web most bright and sure.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(core): restrict web viewport URLs to public http/https' directly and clearly describes the main security fix: validating web URLs to restrict them to public HTTP/HTTPS URLs only, which matches the core changes in the PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-webviewport-local-file-exfiltration

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/hypercolor-core/src/effect/builtin/web_viewport.rs`:
- Around line 401-406: The is_private_or_loopback_ip function fails to detect
IPv4-mapped IPv6 addresses (e.g. ::ffff:127.0.0.1) so those addresses bypass the
IPv4 private/loopback checks; update is_private_or_loopback_ip to recognize
IPv4-mapped IPv6 (in the IpAddr::V6 arm) by extracting the embedded IPv4 address
and applying the same checks used for IpAddr::V4
(is_private/is_loopback/is_link_local), and add the proposed tests asserting
that "::ffff:127.0.0.1" and "::ffff:192.168.1.1" return true while
"::ffff:8.8.8.8" returns false to cover this case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ae3f949c-f07e-4d4c-a3f5-cb3266426926

📥 Commits

Reviewing files that changed from the base of the PR and between b676e31 and d7ca558.

📒 Files selected for processing (1)
  • crates/hypercolor-core/src/effect/builtin/web_viewport.rs

Comment thread crates/hypercolor-core/src/effect/builtin/web_viewport.rs
hyperb1iss and others added 2 commits May 19, 2026 02:06
is_private_or_loopback_ip classified ::ffff:127.0.0.1 and other
IPv4-mapped IPv6 literals only against the V6 predicates, which never
match a mapped loopback or private address. A web viewport URL using
that form would connect to the embedded IPv4 target and slip past the
SSRF policy. Mapped addresses are now unwrapped and checked as IPv4.
@hyperb1iss hyperb1iss force-pushed the codex/fix-webviewport-local-file-exfiltration branch from d7ca558 to 685893a Compare May 19, 2026 09:18
@hyperb1iss hyperb1iss merged commit 72769dd into main May 19, 2026
@hyperb1iss hyperb1iss deleted the codex/fix-webviewport-local-file-exfiltration branch May 19, 2026 09:19
hyperb1iss added a commit that referenced this pull request May 19, 2026
The web viewport SSRF guard from #64 classified hosts through
`Url::host_str()`, which renders IPv6 literals in bracketed form
(`[::1]`). `host.parse::<IpAddr>()` then fails on that bracket text,
so `is_private_or_loopback_ip` was never reached: loopback,
IPv4-mapped loopback, and unique-local IPv6 destinations all slipped
the filter and were fetched freely.

Two narrower gaps rode along. The unspecified addresses `0.0.0.0`
and `[::]` connect to the local host yet matched no private or
loopback predicate. And a trailing dot (`localhost.`) sidestepped
the literal `localhost` comparison while resolving identically.

Match on the parsed `Url::host()` enum so IPv6 literals arrive as
`Host::Ipv6` and reach the classifier, reject unspecified addresses
explicitly, and strip a trailing dot before the local-hostname
check. New tests drive `validate_web_url` with concrete attack URLs
instead of only exercising the IP predicate in isolation.

Co-authored-by: Nova (Claude Opus 4.7) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant