modelcontextprotocol / modelcontextprotocol/inspector

Deep-link auth-token comparison in deepLink.ts isn't constant-time

Open
#2,429 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug v2
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.

  1. clients/web/src/utils/deepLink.ts's parseDeepLink() reads an authToken from 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; and const autoOpen = params.get("autoOpen") === authToken;.
  2. 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.
  3. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.