Skip to content

fix(everything): re-check GZIP_ALLOWED_DOMAINS on redirect hops - #4622

Open
SashaMIT wants to merge 2 commits into
modelcontextprotocol:mainfrom
SashaMIT:fix/everything-gzip-allowlist-redirects
Open

fix(everything): re-check GZIP_ALLOWED_DOMAINS on redirect hops#4622
SashaMIT wants to merge 2 commits into
modelcontextprotocol:mainfrom
SashaMIT:fix/everything-gzip-allowlist-redirects

Conversation

@SashaMIT

@SashaMIT SashaMIT commented Aug 8, 2026

Copy link
Copy Markdown

Description

gzip-file-as-resource validated GZIP_ALLOWED_DOMAINS only against the initial URL, then called fetch with the default redirect policy (follow). An allowlisted host could respond with a 3xx to a host outside the allowlist, and the tool would still download and gzip that body.

This change follows redirects manually (redirect: "manual"), re-applies the same protocol and domain checks on every hop, and caps redirect depth.

Server Details

  • Server: everything
  • Changes to: tools (gzip-file-as-resource)

Motivation and Context

GZIP_ALLOWED_DOMAINS is documented as the domain allowlist for this tool. Without hop re-checks, the control does not hold whenever an allowed origin redirects.

Local confirmation (pre-fix): with allowlist 127.0.0.1, an origin on 127.0.0.1 that 302s to http://[::1]:.../secret returned the IPv6 target body under default fetch redirect following. Post-fix, the same setup rejects [::1] before the second request.

How Has This Been Tested?

  • Added vitest coverage that mocks a 302 from an allowed host to 127.0.0.1 and asserts rejection + that the redirect target is never fetched
  • npm test in src/everything (108 tests) green
  • Dual-stack local HTTP repro green post-fix

Breaking Changes

None for the default (empty allowlist). Operators with GZIP_ALLOWED_DOMAINS set get the documented allowlist behavior on redirect chains as well as on the first URL.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Protocol Documentation
  • My changes follows MCP security best practices
  • I have updated the server's README accordingly
  • I have tested this with an LLM client
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have documented all environment variables and configuration options

Additional context

Framed as a product bug in the existing allowlist control (reference everything server). SECURITY.md notes these servers are reference implementations and not a security-reporting surface; happy to adjust if maintainers prefer a different lane.

Made with Cursor

The gzip-file-as-resource allowlist only validated the initial URL, while
fetch followed redirects by default, so an allowed host could redirect to a
host outside GZIP_ALLOWED_DOMAINS. Follow redirects manually and apply the
same protocol/domain checks on each hop.
@Ecocitizenz

This comment was marked as spam.

Per review: exercise chains where each hop re-validation must hold even
though the destination's textual form changes: hostname to IPv4/IPv6
literal, permitted-to-non-permitted chains, relative Location then
absolute cross-origin, and userinfo authority tricks. Positive control:
relative redirect staying on the allowed host still succeeds. Each
scenario asserts the forbidden destination is never fetched. Fails when
redirect mode is reverted to follow.
@SashaMIT

SashaMIT commented Aug 9, 2026

Copy link
Copy Markdown
Author

Great callouts, thank you. Added coverage in 9791fdb for the representation-change cases: hostname to IPv4 and IPv6 literals, permitted-to-non-permitted chains, relative Location then absolute cross-origin, and the userinfo authority trick. Each scenario asserts the non-allowed destination is never fetched, and there is a positive control that a relative redirect staying on the allowed host still succeeds.

On DNS resolution changing between validation and connection: agreed, that is egress-layer territory. URL-layer validation alone is not complete SSRF containment there; I have noted it as out of scope in the PR description.

@Ecocitizenz

This comment was marked as spam.

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.

2 participants