modelcontextprotocol / modelcontextprotocol/inspector
Deep-link auth-token comparison in deepLink.ts isn't constant-time
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 10.9k
- Forks
- 1.5k
- Avg merge
- 6h 17m
- Merged PRs (30d)
- 151
Description
Which version line?
v2 — current (@modelcontextprotocol/inspector@latest)
Which client?
Web
Inspector version
2.7.0 (git tag) — static code-review finding, not run locally
Node version
N/A — static code review, no live run performed
Operating system (and browser, for the web client)
N/A — static code review
Transport
Not applicable / never connected
MCP server under inspection
N/A — this is a static code-review finding against the 2.7.0 tag's clients/web/src/utils/deepLink.ts, not a live reproduction against a running MCP server.
Steps to reproduce
Found via static review of the 2.7.0 tag source, not a live run.
- clients/web/src/utils/deepLink.ts's parseDeepLink() reads an
authTokenfrom the app's own config and a token from the incoming deep-link URL's query params, then compares them with plain!==/===:if (!authToken || autoConnect !== authToken) return undefined;andconst autoOpen = params.get("autoOpen") === authToken;. - JavaScript's
===on strings short-circuits at the first differing character, so comparison time leaks (very slightly, but measurably in principle) how many leading characters of a guessed token are correct. - This is the same class of issue the project has hardened elsewhere for security-sensitive comparisons (e.g. its documented care around loopback/CIMD checks); a CSRF-style deep-link token comparison is a plausible candidate for the same treatment, since a local attacker (another process, another browser tab) may be able to trigger repeated deep-link opens and time the responses.
No live timing attack was attempted; this is based on reading deepLink.ts against the 2.7.0 tag.
Expected behavior
The deep-link auth-token comparison in parseDeepLink() uses a constant-time comparison (e.g. a timing-safe-equal helper), the same way other security-sensitive token/credential comparisons in the codebase are expected to be handled, so response timing cannot leak how much of a guessed token was correct.
Actual behavior
parseDeepLink() compares the deep-link's autoConnect/autoOpen params against the configured authToken using plain !==/===, which short-circuits on the first mismatched character and so is not constant-time. It's a narrow, largely theoretical local-attacker timing side channel, but it's the kind of comparison this project has otherwise been careful to harden (loopback/CIMD checks, etc.).
Suggested fix: replace the plain string comparison with a constant-time comparison (e.g. compare fixed-length HMACs or use a timing-safe-equal utility) for the authToken check in parseDeepLink().
Logs, errors, or screenshots
No response
Already prototyped a fix?
No response
Before you submit
- I searched existing issues and this is not a duplicate.
- This is not a security vulnerability report (those go through the private advisory process).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in clients/web/src/utils/deepLink.ts at parseDeepLink() and trace both authToken comparisons for their existing callers and validation behavior. Review the codebase's existing security-sensitive comparison approach before choosing the constant-time mechanism. Done means the deep-link token checks no longer use plain short-circuiting string comparisons and existing behavior remains covered by the relevant tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100