Skip to content

Validate static_map_image_tool style path#151

Open
mattpodwysocki wants to merge 3 commits intomainfrom
fix/static-map-style-validation
Open

Validate static_map_image_tool style path#151
mattpodwysocki wants to merge 3 commits intomainfrom
fix/static-map-style-validation

Conversation

@mattpodwysocki
Copy link
Contributor

Summary

Fixes a path traversal vulnerability issue in static_map_image_tool.

  • Path traversal fix: The style parameter was an unvalidated z.string(), allowing a crafted value like ../../tokens/v2 to escape the /styles/v1/ URL path and proxy authenticated requests to arbitrary Mapbox API endpoints using the server operator's access token. Added a regex constraint (/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+$/) that accepts only valid username/style-id format. Also apply encodeURIComponent() to each segment before URL interpolation.

  • Credentials leak fix: The full URL including ?access_token=TOKEN was returned as text content and exposed to the model context. The token is only needed internally for the HTTP fetch and the MCP Apps iframe. Changed to return a public URL (without the token) in the text content block.

Test plan

  • Added test: rejects style values with path traversal patterns — verifies traversal payloads (../../tokens/v2, ../styles, etc.) are rejected with isError: true
  • Updated existing URL tests to assert access_token= is not present in text content
  • All 613 tests pass

🤖 Generated with Claude Code

…atic map URL

- Add regex validation to the style parameter to prevent path traversal attacks;
  accepts only username/style-id with alphanumeric chars, hyphens, and underscores
- Apply encodeURIComponent() to each style segment before URL interpolation
- Return public URL (without access_token) in text content to avoid leaking
  credentials to the model context; token is still used internally for the fetch
  and the MCP Apps iframe URL

Reported via HackerOne (2026-03-18)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mattpodwysocki mattpodwysocki requested a review from a team as a code owner March 18, 2026 18:51
style: z
.string()
.regex(
/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+$/,
Copy link
Contributor

Choose a reason for hiding this comment

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

would something like path.resolve(), path.normalize() be better than regex?

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe not "better" but in addition to regex

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question — but path.resolve()/path.normalize() are the wrong fit here. They operate on filesystem paths and would canonicalize a traversal payload (e.g. ../../tokens/v2/tokens/v2) rather than reject it. The goal is to validate that the input matches a known-good format, not to sanitize an arbitrary path. A whitelist regex that only accepts username/style-id (alphanumeric, hyphens, underscores, exactly one slash) is the right approach — anything outside that shape is rejected outright.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

3 participants