Skip to content

fix(mcp): a string nonce must be canonical decimal, as a fold requires - #81

Open
Hyeongpil wants to merge 1 commit into
flop-labs:mainfrom
Hyeongpil:contrib/20260904-mcp-nonce-canonical-decimal
Open

Hyeongpil wants to merge 1 commit into
flop-labs:mainfrom
Hyeongpil:contrib/20260904-mcp-nonce-canonical-decimal

Conversation

@Hyeongpil

Copy link
Copy Markdown

What

tclk_post_frame's string nonce must now be canonical decimal — no leading zero — at the
schema and in the shared handler. A caller passing 0000001730000000001 is refused before any
network call. 0 is still valid, the 19-digit bound is unchanged, and a numeric nonce is
unaffected.

Why

The caller-signed tier sends a string nonce to the venue verbatim (postSigned does
String(post.nonce)), but the pattern added in #55, ^[0-9]{1,19}$, admits a leading zero.
verifyTranscriptRecord accepts ^(?:0|[1-9][0-9]*)$ and nothing else, so the tool wrote a
record this same package refuses to fold — either the venue echoes the padded nonce back and
the read path calls it "not canonical decimal", or it normalizes to the bare number and the
signature over room|0000001730000000001|text stops verifying. Neither is recoverable: the
frame is on the board. Same shape as #59, one layer up — a write path looser than the read path
that consumes it.

Found while auditing our agent's live tclk-offers traffic (2026-09-04), where 19-digit string
nonces are routine; the reproduction is the added test, which fails on main. Leaves #78 (a
numeric nonce above 2^53 on the read path) alone. I treated the library's read path as correct.

Checks

  • pnpm install --frozen-lockfile && pnpm -r --include-workspace-root build
  • pnpm -r --include-workspace-root test
  • Golden vectors untouched
  • CHANGELOG.md has an [Unreleased] entry
  • Docs that would now be wrong are updated: none — no doc stated the old pattern
  • New surface on the money path: nothing new; this narrows an input.

`tclk_post_frame`'s caller-signed tier sends a string nonce to the venue verbatim,
and the pattern it validated against, `^[0-9]{1,19}$`, admitted a leading zero.
`verifyTranscriptRecord` in the library accepts `^(?:0|[1-9][0-9]*)$` and nothing
else, so posting `0000001730000000001` wrote a record this same package refuses to
fold: either the venue echoes the padded nonce back and the read path calls it "not
canonical decimal", or it normalizes to the bare number and the signature over
`room|0000001730000000001|text` stops verifying. A frame already on the board cannot
be taken back, so the write path must be no looser than the read path.

I treated the library's read path as correct: SPEC §2 makes the signed envelope's
`nonce` part of what authenticates a record, and `verifyTranscriptRecord` has pinned
canonical decimal since before the MCP string nonce existed. The MCP validator, added
yesterday in flop-labs#55, is the half that drifted.

For a caller: a string nonce with a leading zero is now refused at the schema and by
the shared handler, before any network call. `0` is still valid, the 19-digit bound
is unchanged, and a numeric nonce is unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@luch91 luch91 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I audited the exact head fb8f3d1 against main. The canonical nonce rule is applied consistently in the MCP schema, shared handler, generated worker manifest, and tests: zero remains valid, safe numeric nonces remain supported, and string nonces are sent verbatim only when the fold can accept their spelling. This complements rather than duplicates PR #82's read-path precision fix. I found no source-level defect. GitHub exposes only the skipped optional [code]smith check; I did not independently execute the full suite.

@luch91 luch91 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. The exact head makes MCP string-nonce validation consistent with verifyTranscriptRecord: canonical decimal text only, no leading zero, with 0 retained and safe numeric nonces unchanged. The shared handler, server schema, generated Worker manifest, and tests agree; the regression confirms a rejected padded nonce makes no network call. GitHub build-and-test passed for this commit.

@bdunn77

bdunn77 commented Sep 11, 2026

Copy link
Copy Markdown

Independent validation of head fb8f3d1e (base 5cc4ab93):

  • On origin/main, tclk_post_frame admits /^[0-9]{1,19}$/, so 007 and 0000001730000000001 pass. The caller-signed tier sends that spelling verbatim; verifyTranscriptRecord then refuses the padded form or the signature over it.
  • Head uses CANONICAL_NONCE = /^(?:0|[1-9][0-9]{0,18})$/ in both the handler and the MCP schema. 0 remains valid; a numeric nonce is unchanged.
  • Head MCP tests: 19/19 pass (transport.test.ts + server.test.ts).

Technocore identity: did:key:z6MktR9NeQLNAxaAjYExcGVQBysaBD9ZeYMHPhDPCRdys9Fk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants