fix: hold string claims and exp to REQ-COMMON-19 / REQ-COMMON-19D - #3
Merged
Merged
Conversation
Two spec-compliance gaps found in review of #1, both pre-existing on main. REQ-COMMON-19 requires a string claim's match to cover the closing quote AND the following structural byte. Only email_verified and exp asserted their trailing byte; email, nonce, sub, iss and aud stopped at the closing quote, so a claim-shaped substring inside a longer signed string value would have matched -- JSON escaping of attacker-typed content was the only thing in the way. Every claim now ends at `,` or `}` via one shared assert_structural(), and the section-9 bounds grow by one byte so the trailing byte itself must lie inside the authenticated payload length (REQ-COMMON-19B), not in prover-controlled zero padding. REQ-COMMON-19D pins integers to canonical 0|[1-9][0-9]* and lists leading zeros among the rejects; the exp digit-run check accepted them, so a leading-zero rendering was a second signed encoding of the same u64. A multi-digit exp may no longer start with '0'; the lone "0" stays legal. Negative tests cover both: a claim-shaped substring whose apparent closing quote is followed by ordinary string content now fails, as does a leading-zero exp; companion positive tests pin the accepted shapes. The added constraints move jwt_email from 179,367 to 179,413 gates (+46, 0.03 %) and change its vk_hash from 0x24db903f...88a5a69f to 0x1596b429...2af7a27c; the on-chain verifier regenerates with the next release. bearer-link and dyaka-noir-token artifacts are byte-identical. Assisted-by: Claude Fable 5 Signed-off-by: xgreenx <xgreenx9999@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes out the two findings from the review of #1 — both pre-existing on
main, both defense-in-depth misses in
circuits/jwt_email/src/main.nr.Targets the
feat/ceremony-circuitsbranch so it lands as part of #1'shistory; the branch is #1's head plus this one commit.
REQ-COMMON-19 — trailing structural byte on string claims
The spec requires the circuit to "assert the full
"field":"delimiter atthat offset, the value bytes, the closing quote, and the following
structural byte fixed by the profile". Only
email_verifiedandexpasserted their trailing byte; the five string claims —
email,nonce,sub,iss,aud— stopped at the closing quote, so a claim-shapedsubstring inside a longer signed string value would have satisfied the
match, with JSON escaping of attacker-typed content the only thing in the
way.
Every claim now asserts the byte after its match is
,or}through oneshared
assert_structural()(the two existing inline checks fold into it),and the section-9 offset bounds each grow by one byte so the trailing byte
itself must sit inside the authenticated payload length per REQ-COMMON-19B —
without that, the new assertion could be satisfied from prover-controlled
zero padding.
REQ-COMMON-19D — canonical
expThe spec pins integers to canonical
0|[1-9][0-9]*and explicitly listsleading-zero among the rejects. The digit-run check accepted any digits, so
"exp":0123…was a second signed encoding of the same u64. A multi-digitexpmay no longer begin with'0'; the lone"0"remains legal.Tests
Four new tests (jwt_email 3 → 7, repo 24 → 28): a claim-shaped substring
whose apparent closing quote is followed by ordinary string content fails
with the new assertion after passing every pre-existing check, and a
leading-zero
expfails; companion positive tests pin,/}continuations and the two canonical
expshapes (ten-digit timestamp,lone
"0").Artifact impact (pinned toolchain: nargo 1.0.0-beta.20, bb 5.0.0-nightly.20260324)
0x24db903f…88a5a69f0x1596b429…2af7a27cThe README's recorded jwt_email vk_hash is updated accordingly (the
2026-08-12 reproducibility note now dates its hash and records the current
one), and the stale "jwt_email has no tests" comment in ci.yml is corrected.
nargo fmt --check,nargo test(28/28) andscripts/build.shall passlocally under the pinned toolchain.
🤖 Generated with Claude Code