The hosted doctor echoes the stored bearer token back in its own response
- 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:501-513` builds the initialize attempt with the stored token on it:
```ts
if (accessToken) { headers.Authorization = `Bearer ${accessToken}`; }
return { name: "streamable_initialize", request: { method: "POST", url: config.url, headers, … } };
```
That `headers` object is stored on the attempt and ships to the caller inside `transport.attempts[].request.headers`. The token comes from server-side storage (`routes/web/servers.ts:224`, `auth.ts:958-964`), not from the caller's own request. The redactor added in #4884 rewrites `error.message`, `connection.detail`, `checks[].detail` and now `error.code` and `durationMs` — it does not touch `request.headers`.
## Why it matters
The caller is authorized for that server, so this is not a cross-tenant leak. It is a needless echo that puts a live OAuth access token into a JSON response body, which then reaches:
- browser memory and devtools
- HAR exports
- any support bundle or ticket a user pastes it into
A token that never had to leave the server is now in several places nobody is tracking.
## Suggested direction
Redact `Authorization` (and any other credential-shaped header) out of `attempts[].request.headers` unconditionally, hosted or not. The attempt record is for diagnosing the request shape; the secret value carries no diagnostic weight.
## Notes
Separate from #5000 (credential headers egressing to target-chosen metadata hosts), 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:501-513 and trace how the stored token enters the attempt record and reaches the response. Review routes/web/servers.ts:224 and auth.ts:958-964 for the token source, then inspect existing probe coverage if available. Done means credential values, including Authorization, are absent from attempts[].request.headers while the request shape remains diagnosable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100