Skip to content

fix(server): admit the reached IP on a wildcard bind; isolate the ori… - #128

Closed
hyperpolymath wants to merge 2 commits into
mainfrom
fix/wildcard-origin-and-test-isolation
Closed

hyperpolymath wants to merge 2 commits into
mainfrom
fix/wildcard-origin-and-test-isolation

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

…gin tests from the environment

Both CodeRabbit functional-correctness findings from PR #120, accepted.

Wildcard bind: the origin allow-list excludes wildcard addresses and the Host check runs on loopback binds only, so a UI served from a wildcard bind (start(host="0.0.0.0")) received 403 on every write: the browser sends Origin on same-origin POSTs, and the served address (http://192.168.1.10:8080) was not in _allowed_origins(). The operator's only recourse was to list the machine's address in JULIA_METAMANIFOLD_ALLOWED_ORIGINS, which the README documents for split deployments but which makes the plain wildcard-served UI unusable for writes.

The guard now admits, on a wildcard bind, an origin that names the request's own IP: an http origin whose host is an IP literal (IPv4 or bracketed IPv6, never a name), on the bound port, whose host-and-port equals the Host header. A browser sends such an Origin only for a page it loaded from exactly that address, so the request is same-origin by construction; a DNS-rebinding page arrives with the attacker's domain as both Host and Origin, and a name is not an IP literal, so it is refused as before. Hostnames and proxied ports must still be listed in JULIA_METAMANIFOLD_ALLOWED_ORIGINS.

Test isolation: the baseline origin assertions in
test_server_security.jl assumed JULIA_METAMANIFOLD_ALLOWED_ORIGINS was unset; the suite failed for a developer running it with the variable set (a supported deployment setting). It is now cleared before the testset and restored in the finally.

Tests: a new wildcard-bind testset covers the admitted IP (GET with CORS echo, preflight 204, a POST that reaches the route), the admitted IPv6 literal, other addresses, ports and schemes refused, the rebinding shape refused, and a listed hostname required without the variable. Verified locally both with the variable unset (86/86 in the file, 2636 passed in the full suite) and set to
"http://localhost:3000, http://192.168.1.10:8080" (still 86/86; the same run on main fails 4 tests).

Generated by Mistral Vibe.

Summary

Closes #

Type of change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (would change existing behaviour)
  • 🕳️ Soundness fix (fixes a checker/proof false-negative)
  • 📖 Documentation
  • 🧹 Refactor / tech debt (behaviour-preserving)
  • ⚡ Performance
  • 🔧 Build / CI / tooling

How has this been verified?

Checklist

  • My commits are signed (git commit -S).
  • I ran the project's own checks/tests locally and they pass.
  • New files carry the correct SPDX-License-Identifier (code/config MPL-2.0,
    prose CC-BY-SA-4.0); I did not relicense existing files.
  • Docs are updated, and no public claim now overstates what the code does.
  • I have not introduced a soundness hole (or I have flagged where I might have).

Notes for reviewers

…gin tests from the environment

Both CodeRabbit functional-correctness findings from PR #120, accepted.

Wildcard bind: the origin allow-list excludes wildcard addresses and the
Host check runs on loopback binds only, so a UI served from a wildcard
bind (start(host="0.0.0.0")) received 403 on every write: the browser
sends Origin on same-origin POSTs, and the served address
(http://192.168.1.10:8080) was not in _allowed_origins(). The operator's
only recourse was to list the machine's address in
JULIA_METAMANIFOLD_ALLOWED_ORIGINS, which the README documents for split
deployments but which makes the plain wildcard-served UI unusable for
writes.

The guard now admits, on a wildcard bind, an origin that names the
request's own IP: an http origin whose host is an IP literal (IPv4 or
bracketed IPv6, never a name), on the bound port, whose host-and-port
equals the Host header. A browser sends such an Origin only for a page
it loaded from exactly that address, so the request is same-origin by
construction; a DNS-rebinding page arrives with the attacker's domain as
both Host and Origin, and a name is not an IP literal, so it is refused
as before. Hostnames and proxied ports must still be listed in
JULIA_METAMANIFOLD_ALLOWED_ORIGINS.

Test isolation: the baseline origin assertions in
test_server_security.jl assumed JULIA_METAMANIFOLD_ALLOWED_ORIGINS was
unset; the suite failed for a developer running it with the variable set
(a supported deployment setting). It is now cleared before the testset
and restored in the finally.

Tests: a new wildcard-bind testset covers the admitted IP (GET with CORS
echo, preflight 204, a POST that reaches the route), the admitted IPv6
literal, other addresses, ports and schemes refused, the rebinding
shape refused, and a listed hostname required without the variable.
Verified locally both with the variable unset (86/86 in the file,
2636 passed in the full suite) and set to
"http://localhost:3000, http://192.168.1.10:8080" (still 86/86; the
same run on main fails 4 tests).

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 42 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: d48bea32-0872-4020-a9f7-59f41ddb83c4
📥 Commits

Reviewing files that changed from the base of the PR and between ebebed2 and 525c280.

📒 Files selected for processing: 2
  • src/server/server.jl
  • test/unit/test_server_security.jl
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath

Copy link
Copy Markdown
Owner Author

Closing as a duplicate: this branch's work (the wildcard-origin bind and origin-test isolation) already merged as #121. The sweep re-opened the leftover branch against a base it predates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant