Skip to content

fix(scan): reject non-canonical operation counts (#99)#100

Merged
LiranCohen merged 1 commit into
mainfrom
fix/scan-canonical-opcount
Jun 8, 2026
Merged

fix(scan): reject non-canonical operation counts (#99)#100
LiranCohen merged 1 commit into
mainfrom
fix/scan-canonical-opcount

Conversation

@LiranCohen

Copy link
Copy Markdown
Contributor

Summary

Closes audit finding #15 (consensus parity). ExtractFromScript parsed the anchor-string operation count with strconv.Atoi (only err/negative checked). The Sidetree reference accepts only /^[1-9][0-9]*$/; Atoi also accepts +5, 007, 0 — so ion-node indexed and applied operations from crafted anchors that canonical ION ignores, silently diverging DID resolution.

Fix

  • internal/scan/opreturn.go: canonicalCount(s) enforces ^[1-9][0-9]*$ (positive decimal, no sign, no leading zeros, no overflow), replacing the lenient Atoi. This also rejects 0-count anchors at scan time, so they no longer consume a per-block tx-cap slot (partial overlap with feat(process): pending-CID retry loop with backoff + late splice (M4 U6) #26).
  • internal/scan/opreturn_test.go: TestExtractCanonicalOpCount table-tests accepted (5/1/100/10000) vs rejected (0, 007, +5, -5, whitespace, 0x5, overflow, empty).

go test -race ./... green (26 packages). Existing indexer tests use canonical 1.<cid> anchors, unaffected.

Post-Deploy Monitoring & Validation

  • What to watch: purely a tightening of accepted anchors. On mainnet, legitimate ION anchors always use canonical counts, so indexed-anchor volume should be unchanged; only crafted/malformed anchors are now (correctly) dropped, matching canonical ION.
  • Failure signal / trigger: none expected; a drop in legitimately-indexed anchors would be surprising and worth investigating.
  • Window/owner: compare indexed-anchor counts across the upgrade on a synced node.

Closes #99

🤖 Generated with Claude Code

Finding #15. ExtractFromScript parsed the anchor-string op count with strconv.Atoi
(only err/negative checked). The Sidetree reference accepts only /^[1-9][0-9]*$/;
Atoi also accepts "+5", "007", "0", so ion-node indexed operations from crafted
anchors canonical ION ignores — silently diverging DID resolution.

- internal/scan/opreturn.go: canonicalCount(s) enforces ^[1-9][0-9]*$ (positive
  decimal, no sign, no leading zeros, no overflow), replacing the lenient Atoi. Also
  rejects "0"-count anchors at scan time (they no longer consume a per-block tx-cap
  slot — partial overlap with #26).
- internal/scan/opreturn_test.go: TestExtractCanonicalOpCount table-tests accepted
  (5/1/100/10000) vs rejected (0, 007, +5, -5, whitespace, 0x5, overflow, empty).

go test -race ./... green.

Co-authored-by: Liran Cohen <liranlasvegas@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@LiranCohen LiranCohen merged commit b1e7bcb into main Jun 8, 2026
1 check passed
@LiranCohen LiranCohen deleted the fix/scan-canonical-opcount branch June 8, 2026 02:49
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.

scan: non-canonical operation counts ('+5','007','0') are accepted, diverging from canonical ION

1 participant