v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
MEDIUM AI PREVALENCE: MEDIUM auth.mcp.predictable-session-id

This MCP StreamableHTTPServerTransport derives its session id from a predictable source: Date.now(), Math.random(), or an incrementing counter (CWE-330).

Why AI tools produce this: AI coding tools produce this regularly, typically when prompted for a shortcut or a quick fix.

Why this matters

Session ids are the bearer of the MCP session; if an attacker can guess or enumerate them, they can hijack another client's session and issue tool calls as that client. Math.random() is not a CSPRNG and time/counter values are trivially predictable.

Use a cryptographically secure generator: sessionIdGenerator: () => randomUUID() // from node:crypto (Omit sessionIdGenerator entirely for stateless mode, which is fine.)

VULNERABLE
vulnerable.ts
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

// ruleid: auth.mcp.predictable-session-id
const t1 = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => Date.now().toString(),
  enableDnsRebindingProtection: true,
});

// ruleid: auth.mcp.predictable-session-id
const t2 = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => `sess-${Math.random()}`,
});

let counter = 0;
// ruleid: auth.mcp.predictable-session-id
const t3 = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => String(counter++),
});
SAFE
safe.ts
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { randomUUID } from 'node:crypto';

// CSPRNG-backed session id: safe.
const t1 = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => randomUUID(),
  enableDnsRebindingProtection: true,
});

// Stateless mode (no session ids): safe.
const t2 = new StreamableHTTPServerTransport({
  sessionIdGenerator: undefined,
});

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

// oauthlint-disable-next-line auth.mcp.predictable-session-id -- <reason>

References

https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization ↗https://cwe.mitre.org/data/definitions/330.html ↗