Repository navigation
fix(auth): backport dot-segment and redirect refusals - #7599
Conversation
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 4a0ab07
No actionable bugs found. The focused release backport puts dot-segment refusal before admission dispatch and disables redirects on the shared auth HTTP client, covering connect, revalidate, and end without adding a new policy layer. Keeping request spelling intact and using reqwest’s existing redirect policy are simpler than normalization or destination-specific redirect rules. The added regressions check encoded dot variants and that redirect destinations receive no credential-bearing requests.
Verification: static review of the changes and relevant admission/client code only. I did not run tests, builds, or live authentication checks.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
A faithful release backport of two main auth hardening fixes, carried by one commit across three files.
- Dot-segment refusal (
rs/moq-relay/src/auth.rs):Auth::admitrefuses a path with a.or..segment, literal or%2e-encoded, before the admission reaches any decider. The newnavigateshelper is byte-identical tomain's, and dotted names (/a/...,/.hidden,/a/%252e) keep their exact spelling. - Redirect refusal (
rs/moq-auth/src/client.rs): the auth HTTP client setsredirect::Policy::none(), and a newchecktreats any non-2xx, redirects included, asError::Unavailable.post_endswapserror_for_status()(which accepted 3xx) forcheck. 401/403 still map toError::Refused. - Docs and tests:
doc/bin/relay/auth.mddocuments both refusals; regressions cover the admission boundary and real mock servers across 301/302/303/307/308 and all three auth events, asserting the redirect destination receives nothing.
I verified navigates and check match origin/main exactly, that Error::Request is the relay's own variant (HTTP 400) rather than a moq-auth one, and that the single %2e check is sufficient under WHATWG URL semantics (an encoded slash is not a path separator, so %2f is not a bypass). Keeping release's client-wide TIMEOUT while main drops it is an intentional, documented divergence.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
|
This run hit its 1h time limit while still working. Give runs longer with
|
|
Post-landing validation, resumed after moq-dev/moq#7594 fixed the mbx
Details are in moq-dev/moq#7596. The fix shipped in (Written by Claude Opus 5.5) |

Problem
releaseforwards raw dot-segment connection paths to the auth decider and follows redirects from the auth server. A 307/308 can resend the credential-bearing JSON body to another destination.Tracking quest: quest/m0/backport-release-hardening.md, claimed in moq-dev/moq#7596.
Approach
Hand-port the dot-segment refusal from moq-dev/moq#7366 and auth redirect refusal from moq-dev/moq#6384.
Auth::admitrejects literal and percent-encoded./..segments before queueing an admission. Ordinary names containing dots retain their exact spelling.Impact
Alternatives
A cherry-pick would bring main-only auth structure into
release. Normalizing connection paths would rewrite what the decider sees. Refusing them matches main and URL dot-segment semantics; disabling redirects uses reqwest's existing policy.Choices made without asking
Use the existing embedded admission queue to prove refused paths never reach any decider, rather than importing main's tenant-matrix harness. Share main's private response-status check between auth grants and end reporting, because
error_for_statusalone accepts 3xx responses. Keep the main quest checkpoint separate from thisreleasecode PR, as moq-dev/moq#7381 does.Validation
Current head
4e9d023d4d1bab841e50e08def0aeac4a3290f53mergesreleaseat8b1fa1dc0f(moq-dev/moq#7586, benches) into the reviewed fix commit4a0ab0770f. The merge was conflict-free.git diff origin/release...HEADis byte-identical to the reviewed head's diff against its old base: 3 files, +125/−15.Rerun on the merged head, inside this branch's
nix develop, with no PATH workaround:just ci check origin/release: pass, including clippy, formatting, rustdoc, JS check/build, actionlint, andnix flake check("all checks passed!").just ci test origin/release: pass. Rust: 588 passed, 2 skipped, plus 133 passed (moq-cli). All JS suites pass.quest check --base origin/release: pass.Argument list too long (os error 7)from mbx.Earlier, on
4a0ab0770fbefore the merge:307 forwarded Connect to the redirect destination. After the fixes, both pass.just rs uring-check: pass.sh/api-diff/run.sh --deny rustagainstorigin/release: every published crateunchanged, includingmoq-auth0.2.2 andmoq-relay0.17.10.Review
Claude Code,
claude-fable-5-1, medium effort, round 1 (quest review --base origin/release --deep). The author was Codex, so Claude is the other vendor. Reviewed head:4a0ab0770ff477f921fdcfd86ab1c38e48b5db7a. No findings.That review still covers current head
4e9d023d4d1bab841e50e08def0aeac4a3290f53under both exemptions in the guide. The only commit since is a conflict-free merge fromrelease, and the PR's diff againstreleaseis identical to the reviewed head's. The newrs/moq-relay/benches/http_auth.rsfromreleaseuses no redirects or 3xx statuses.Posted reviews on
4a0ab0770f: the OpenAI automated review and pullfrog both report no issues. A later pullfrog run (the only failing check, which is optional) hit its 1h time limit and reported no findings.Also confirmed:
releasealready disables redirects in the relay's outbound HTTP client (rs/moq-relay/src/http_client.rs), and main's mesh auth client doesn't exist onrelease. This auth client was the only redirect-following path to backport.Follow-ups
None identified. This PR belongs in the already planned combined patch release; the maintainer chooses versions and cuts it separately.
(Written by GPT-6.1 Sol; validation and review record updated by Claude Opus 5.5)