Stored credential headers are sent to metadata hosts the target chooses
- Dominant language
- TypeScript
- Stars
- 2.2k
- Forks
- 283
- Avg merge
- 11h 47m
- Merged PRs (30d)
- 737
Description
Found during the review of #4884 (MJ-001 redaction). Out of scope for that PR, deliberately left for its own ticket. Not covered by anything merged.
## What happens
`sdk/src/server-probe.ts:563` strips exactly one header before dialling an authorization-server metadata host:
```ts
const metadataHeaders = removeAuthorizationHeader(normalizeHeaders(config.headers));
```
`removeAuthorizationHeader` (`:139-147`) filters the single name `Authorization`. Every other stored header on the server config is sent as-is — `X-Api-Key`, `X-Auth-Token`, a vendor session header, anything a user saved against that server.
The hosts it sends them to are **named by the target** in its own `WWW-Authenticate` challenge (`resource_metadata`, and the authorization-server metadata URL), not by the user. The egress guard permits them because they are publicly routable.
## Why it matters
A user saves an MCP server with `X-Api-Key: `. The target answers 401 with `resource_metadata="https://collect.attacker.test/prm"`. The probe dials that host and sends the vendor key.
Cross-origin *redirects* already strip credentials (`hosted-egress-guard.ts:435-448`). The initial cross-origin dial to the challenge-named host does not.
## Suggested direction
Strip all stored credential headers — not a denylist of one name — before any request to a host the user did not configure. The existing redirect-stripping logic is the right precedent to reuse.
## Notes
Separate from #5001 (bearer token echoed back in the response), though both live on the same probe path.
Not a pentest finding. Reported here so it is tracked rather than sitting only in the review write-up.
Contributor guide
Research direction
Start in sdk/src/server-probe.ts at lines 563 and 139-147, then compare the credential handling with hosted-egress-guard.ts:435-448. Trace requests to challenge-named metadata hosts and reuse the existing redirect-stripping precedent. Done means stored credential headers are not sent to hosts the user did not configure, while the existing cross-origin redirect behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- networking, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100