MCP signed upload URLs stay reusable after an UNKNOWN source-add
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.mdandSECURITY.mdthat 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)
Source: teng-lin/notebooklm-py