MCP signed upload URLs stay reusable after an UNKNOWN source-add

Author: teng-linCreated Sep 6, 2026Updated Sep 6, 2026
LabelsbugP2

Bug

MCP /files/ul HMAC URLs are scoped, expiring bearer capabilities. They are not strictly single-use.

The jti is burned only after reported success. On unconfirmed / UNKNOWN source-add, validation errors, 429, or disconnect, jti_store.rollback(jti) runs so the same URL can be retried (src/notebooklm/mcp/_fileroutes.py).

That is intentional for “bytes never reached NotebookLM.” Codex’s offline probe: an UNKNOWN add (registration may have committed) then a second successful create through the same URL. The route warns about duplication but still releases the capability.

This is a hosting retry policy issue. It does not reopen the library transport-replay / ReplayGrant work.

Required change

Decide explicitly, then implement and document:

  • A (safer): UNKNOWN / unconfirmed add freezes the jti until the operator reconciles (source_list / pending wait). Do not allow a second create on the same capability. Offer a distinct retry token only after confirmed absence.
  • B (current, documented): UNKNOWN leaves the link retryable; the warning is the only guard. State in docs/mcp-guide.md and SECURITY.md that a leaked or retried upload URL can create two sources.

Do not silently keep B while calling the tokens “single-use.”

TTL, size caps, CORS *, and “HMAC is the only auth on /files/*” stay as the experimental remote-file contract (ADR-0024) unless this issue is expanded.

Tests

  • UNKNOWN add → second POST with same token: either 409/frozen or documented duplicate (per chosen policy)
  • Clean validation/size failure still retryable
  • Confirmed success still burns the jti (second POST rejected)