π Before claiming this issue
Two quick steps before you open a PR:
- β Star the repository β low-friction signal that you'll follow through
- π¬ Comment
I'll take this (or similar) below β prevents two contributors racing on the same issue
Full policy: CONTRIBUTING.md β How to claim. If a claim is older than 7 days with no PR, you can reclaim it politely.
Tracks follow-up #2 from PR #17 security review. Blocked on mcp-server-v1 M3 (~Jul 28, 2026).
What
MCPPairingPanel compares the user-entered token to the expected token using === (constant-time-unsafe). Use a timing-safe comparison.
Why
=== short-circuits on the first byte difference, leaking the prefix-length-match through timing. For a 32-byte token, an attacker controlling the input can extract the correct token byte-by-byte via timing oracle in O(256 Γ 32 Γ N samples) requests. This is the textbook side-channel attack pattern.
The Web Crypto API has crypto.subtle.timingSafeEqual (proposed) β until that's universal, the manual fallback is a XOR-accumulator loop.
Acceptance criteria
Implementation hint
// src/utils/crypto.ts
/**
* Compare two strings in constant time relative to the longer string's length.
* Use this for token / secret comparisons to avoid timing side-channel attacks.
*
* NOTE: Once Web Crypto's timingSafeEqual ships universally
* (https://github.com/whatwg/webcrypto/issues/270), prefer that. For now:
*/
export function timingSafeEqual(a: string, b: string): boolean {
const maxLen = Math.max(a.length, b.length);
let mismatch = a.length !== b.length ? 1 : 0;
for (let i = 0; i < maxLen; i++) {
const ca = i < a.length ? a.charCodeAt(i) : 0;
const cb = i < b.length ? b.charCodeAt(i) : 0;
mismatch |= (ca ^ cb);
}
return mismatch === 0;
}
Context
Tracks follow-up #2 from PR #17 security review. Blocked on
mcp-server-v1M3 (~Jul 28, 2026).What
MCPPairingPanel compares the user-entered token to the expected token using
===(constant-time-unsafe). Use a timing-safe comparison.Why
===short-circuits on the first byte difference, leaking the prefix-length-match through timing. For a 32-byte token, an attacker controlling the input can extract the correct token byte-by-byte via timing oracle in O(256 Γ 32 Γ N samples) requests. This is the textbook side-channel attack pattern.The Web Crypto API has
crypto.subtle.timingSafeEqual(proposed) β until that's universal, the manual fallback is a XOR-accumulator loop.Acceptance criteria
MCPPairingPanel.tsxcompares user input to expected token via a timing-safe helper (no===on the raw token strings)src/utils/crypto.ts(or similar) with JSDoc + a comment citing the side-channel rationaleperformance.now()x 1000 iterations + std-dev assertion)Implementation hint
Context