Fix CI: patch RUSTSEC-2026-0185/0189, add Host allowlist and first tests - #2
Merged
Conversation
cargo audit failed the Security Audit job on two advisories: - quinn-proto 0.11.14 -> 0.11.16 (RUSTSEC-2026-0185, 7.5, remote memory exhaustion) - rmcp 1.2.0 -> 1.8.0 (RUSTSEC-2026-0189, 8.8, DNS rebinding in the Streamable HTTP server transport -- the one this server uses) rmcp >=1.4 fixes the rebinding hole by validating the inbound Host header against an allowlist that defaults to loopback only. Since --http binds 0.0.0.0 and the README documents that mode for MCP gateways, taking the patch as-is would have turned CI green while silently 403-ing every non-localhost deployment. WM_ALLOWED_HOSTS adds hostnames on top of the loopback defaults (additive, so local health checks keep working); a single '*' disables validation and logs a warning. StreamableHttpServerConfig became #[non_exhaustive], so config construction moves from a struct literal to the builder API. Also bumps anyhow 1.0.104 and rand 0.10.2, clearing the three remaining "unsound" warnings -- cargo audit is now completely clean. Verified: fmt, clippy -D warnings, test and audit all pass, plus a smoke test confirming loopback and allowlisted hosts return 200 while a foreign Host gets 403. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLxwTsE7P4RmNskk9LuV9L
The crate had no tests at all, so the "Build & Test" CI job guarded
nothing. These cover the two areas where a silent regression is most
costly: gateway scope filtering and the new Host allowlist.
The scope tests read the tool list from the live router rather than a
hand-kept array, so tools added later are covered without touching them.
The key invariant is that every package_* tool keeps the "deploy" scope
-- a new match arm naming individual package tools ahead of the generic
one silently drops them out of "deploy", and nothing fails at startup.
Verified by reintroducing that exact regression: the test fails with the
offending tool and its resulting scope set. Two further invariants guard
undocumented scopes and admin tools leaking into "develop".
Host-allowlist merging moves out of run_http into config::resolve_allowed_hosts
so it can be tested directly: extra hosts are added to the loopback
defaults rather than replacing them, duplicates collapse, and "*"
disables validation only as a whole entry ("*.example.com" is not
wildcard syntax and must not switch validation off).
Clippy now runs with --all-targets so test code is linted too; without it
CI would not have caught the items_after_test_module violation these
tests introduced.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLxwTsE7P4RmNskk9LuV9L
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.
The Security Audit job has been failing since 26 June.
cargo auditflagged two advisories:quinn-protormcpWhy this isn't just a version bump
RUSTSEC-2026-0189 affects the Streamable HTTP server transport — the one this server uses. Upstream fixes it by validating the inbound
Hostheader against an allowlist that defaults to loopback only.Since
--httpbinds0.0.0.0and the README documents that mode "for MCP gateways", taking the patch as-is would have turned CI green while silently403-ing every non-localhost deployment.So the secure default is kept and
WM_ALLOWED_HOSTSopts hostnames in. Entries are added to the loopback defaults rather than replacing them, so local health checks keep working once a public hostname is configured:StreamableHttpServerConfigbecame#[non_exhaustive]in rmcp 1.4, so config construction moves to the builder API.anyhow1.0.104 andrand0.10.2 clear the three remaining "unsound" warnings —cargo auditis now completely clean.First tests
The crate had no tests at all, so the "Build & Test" job guarded nothing. These cover the two places a silent regression costs most.
Scope filtering. The tests read the tool list from the live router rather than a hand-kept array, so tools added later are covered automatically. The key invariant: every
package_*tool keeps thedeployscope. A new match arm naming individual package tools ahead of the generic one drops them out ofdeploywith nothing failing at startup — this is not hypothetical, it is exactly what #1 currently does. Verified by reintroducing that regression:Two further invariants catch undocumented scopes and admin tools leaking into
develop.Host allowlist. Merging moves out of
run_httpintoconfig::resolve_allowed_hostsso it can be tested directly: additive merge, duplicate collapsing, and*disabling validation only as a whole entry (*.example.comis not wildcard syntax and must not switch validation off).Clippy now runs with
--all-targetsso test code is linted too — without it CI would not have caught theitems_after_test_moduleviolation these tests introduced.Verification
fmt,clippy --all-targets -D warnings,test(15 passing) andauditall pass locally. Plus a smoke test against the real binary:HostsentWM_ALLOWED_HOSTS=mcp.example.comlocalhost:18080mcp.example.comevil.example.com🤖 Generated with Claude Code
https://claude.ai/code/session_01QLxwTsE7P4RmNskk9LuV9L