Skip to content

fix: reject two deserialize-time over-acceptances (v6 audit)#907

Open
mwaddip wants to merge 2 commits into
ergoplatform:developfrom
mwaddip:fix/v6-audit-reject-arms
Open

fix: reject two deserialize-time over-acceptances (v6 audit)#907
mwaddip wants to merge 2 commits into
ergoplatform:developfrom
mwaddip:fix/v6-audit-reject-arms

Conversation

@mwaddip

@mwaddip mwaddip commented Jun 14, 2026

Copy link
Copy Markdown

Two deserialize-time over-acceptances found in a v6 audit — sigma-rust accepted where sigma-state 6.0.3 rejects at parse (oracle-blessed reject vectors).

  1. ValDef.id > Int.MaxValue (REL-WIRE-ID-01): JVM ValDefSerializer reads the id with getUIntExact (rejects > 0x7fffffff); we read it unbounded. New ValId::sigma_parse_exact bounds ValDef.id only — ValUse/FuncValue keep the wrapping getUInt().toInt.

  2. pre-v3 PropertyCall (V6-PROPERTY-TYPEARG-GATE-01): MethodCall already gates tree_version < method.min_version; PropertyCall did not, so a v6 property (Global.none[UnsignedBigInt]) in a pre-v3 tree was accepted — even in a dead if branch, since parse is structural. Same gate added.

Each commit is individually green (tests + fmt + clippy).

mwaddip and others added 2 commits June 14, 2026 22:03
JVM `ValDefSerializer.parse` reads `ValDef.id` with `getUIntExact`
(`getUInt().toIntExact`), rejecting an id VLQ above `0x7fffffff` at
deserialize (ArithmeticException, before any eval). sigma-rust read the id
with the shared unbounded `ValId::sigma_parse` (`get_u32`) and accepted ids
up to `0xffffffff`, binding + evaluating where the JVM rejects.

Add `ValId::sigma_parse_exact` (rejects `> i32::MAX`) and use it for
`ValDef.id` only. `ValUse`/`FuncValue` ids stay on the wrapping
`getUInt().toInt` path (`ValId::sigma_parse`) — bounding them would
over-reject. The `ValId` Arbitrary is constrained to in-range ids so
`ValDef` still round-trips.

Reject vector: ValDef.id_int_max_bound (SANTA v6 audit, REL-WIRE-ID-01).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rsion

JVM `SMethod.fromIds` rejects a method whose required ErgoTree version
exceeds the tree's, at deserialize. `MethodCall::sigma_parse` mirrors this
(`r.tree_version() < method.min_version → Err`) but `PropertyCall::sigma_parse`
did not. A v6 property in a pre-v3 tree — e.g. `Global.none[UnsignedBigInt]`
(min_version V3) — was therefore accepted. Parsing is structural over the
whole tree, so this holds even when the property sits in a dead `if` branch
(deserialize does not lazily skip it).

Add the same gate to `PropertyCall::sigma_parse`. v3 trees are unaffected
(V3 < V3 is false); V0 properties (Context.dataInputs, …) are unaffected.

Reject vector: Global.none_pre_v3_dead_branch (SANTA v6 audit,
V6-PROPERTY-TYPEARG-GATE-01).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant