Validation-Output Nonconsumption / Assigned-But-Unconstrained Check Result
- Name: validation-output nonconsumption / assigned-but-unconstrained check result
- Category: exploit pattern / zk-circuit soundness failure / validation-gadget output omission / under-constrained admission check
- Summary: This pattern appears when a circuit instantiates the right validation gadget — range check, bigint formatter, subgroup test, parser accept-state check, selector sanity check, or similar — but never actually constrains the gadget’s success output. In ordinary software review, the presence of the helper looks reassuring because the validation code is visibly there. In a constraint system, though, an unconsumed
outsignal is only commentary. The prover can satisfy the rest of the circuit while the validation gadget quietly outputs0, so malformed or out-of-domain inputs reach security-critical logic that operators believed had already been screened. - What it is:
- A circuit relies on helper gadgets that expose a boolean or small summary output such as
out,isValid,lt,ok, oraccepted. - Those helpers often also perform internal limb formatting, bit decomposition, or parser-state work that makes the surrounding code look complete.
- The outer circuit wires attacker-controlled inputs into the helper but never constrains the helper’s success output to the required value.
- The proof therefore authenticates a weaker statement than reviewers intended:
the gadget was instantiatedrather thanthe validation succeeded. - Downstream arithmetic, signature verification, state-transition logic, or identity recovery then runs under assumptions that are not actually enforced by the statement.
- A circuit relies on helper gadgets that expose a boolean or small summary output such as
- Typical preconditions:
- The proving system uses reusable helper gadgets whose success condition is surfaced as an output signal rather than enforced internally with a hard equality.
- The outer circuit is optimized or modularized, so validation and business logic live in separate templates.
- Reviewers or implementers assume
calling the validatoris equivalent toenforcing the validator. - The unchecked validation concerns security-critical structure: field bounds, bigint formatting, subgroup membership, deterministic parser acceptance, selector legitimacy, or transition preconditions.
- A successful proof directly authorizes something economically or logically meaningful, such as signature validity, identity authenticity, bridge release, or state-transition acceptance.
- Common vulnerable surfaces:
- bigint and field-range comparators whose
outmust be asserted to1 - parser or regex accept-state gadgets where the final accepting-state condition is computed but not bound into the statement
- curve-point, subgroup, or coordinate checks that produce a boolean validity flag the outer circuit ignores
- selector or branch-legitimacy gadgets whose result only influences an unconstrained intermediate signal
- accumulated validation counters or sums that are computed but never finally constrained
- any
isValid/lessThan/belongsToFieldcomponent instantiated for reviewer comfort but not consumed by the actual relation
- bigint and field-range comparators whose
- Exploit sequence:
- The attacker identifies a security-critical validation gadget whose success output is not constrained by the outer circuit.
- They choose malformed, out-of-range, or semantically invalid inputs that make the helper’s success output false.
- Because no constraint demands
out = 1, proof generation still succeeds as long as the rest of the circuit can be satisfied. - The resulting proof convinces the verifier of a weaker statement that omits the intended admission or sanity check.
- A contract, bridge, or application consumer treats that proof as if the validation had really succeeded.
- The attacker converts the missing check into forged identity, signature acceptance, bad state transition, spoofed parser result, or another downstream privilege.
- Variants:
- Unasserted boolean validator — the helper computes the right
0/1answer, but the outer circuit never requires1, as in circom-pairing’sBigLessThanomission. - Validation-sum without final equality — several checks are accumulated into a counter, yet the final
sum === expectedassertion is missing. - Dead-end validation lane — the helper output is routed into an intermediate signal or branch that does not ultimately constrain the statement.
- Formatting-without-admission — the helper performs limb formatting or decomposition work, creating the appearance of strong validation, but the decisive comparison or membership flag still goes unconstrained.
- Parser-acceptance nonconsumption — automaton or regex circuits compute an accept state, but the proof statement never forces the final state to be one of the accepted states.
- Unasserted boolean validator — the helper computes the right
- Detection heuristics:
- Search for validation gadgets that expose an output signal and audit every path from that output to a hard constraint.
- Treat helper names like
IsValid,BigLessThan,LessThan,Check,accept,isMember, orisOnCurveas suspicious until you can point to the exact enforcing equality. - Diff
inputs wired into the validatoragainstoutputs the final statement actually constrains; the dangerous gap is often just one missing=== 1. - Build negative tests with obviously invalid inputs and ask whether proof generation still succeeds.
- When a circuit comment says
check X, verify that the check’s success bit is consumed by the final relation rather than merely computed. - Be especially suspicious when the helper also performs internal normalization or decomposition work; those internal constraints can make the gadget look more authoritative than it is.
- Defenses:
- Prefer fail-closed helper designs for mandatory checks: if a validation must hold, encode the requirement inside the helper or immediately constrain the output at the call site.
- Treat validation outputs as security-critical API edges. A gadget returning
outis not safe until the caller proves whatoutmust be. - Where multiple checks are aggregated, always end with one explicit constraint on the aggregate result.
- Add negative regression vectors for malformed inputs and require proof generation or verification to fail, not merely
outto evaluate to0in debug traces. - Keep validation helpers and their call-site assertions together in review scope; modularity should not hide the security boundary.
Three validator-output promotions reviewers should not collapse
- A validation-shaped computation exists
- The circuit instantiated a helper such as
LessThan,BigLessThan,IsValid, subgroup membership, parser acceptance, or selector sanity. - This is the weakest and most cosmetic step. It proves only that the code contains a validation lane reviewers can point at.
- The circuit instantiated a helper such as
- That computation became canonical admission truth for the live statement
- This is the decisive step preserved by this pattern: the circuit must force
out = 1,accepted = 1,allChecks == expected, or equivalent so the statement cannot be satisfied while the helper says fail. - If the output never hits that binding edge, the circuit proves
validator was wiredrather thanvalidation succeeded.
- This is the decisive step preserved by this pattern: the circuit must force
- That admitted statement still deserves downstream authority
- A verifier, bridge, signature checker, identity system, or settlement consumer then treats the accepted statement as if malformed inputs were already impossible.
- This is where the omission cashes out: one dead validator output becomes forged signature acceptance, counterfeit identity, invalid state transition, or another authority-bearing proof artifact.
- Review should keep these three questions separate:
did a helper run,did the statement require its success, andwhat downstream authority inherits from that accepted statement.
What sound design looks like
- Mandatory validation should be statement-level truth, not a side computation. If the design intends
all coordinates are < qorthe parser ended in an accept state, then the proof should make that fact unavoidable, not merely computable. The healthy circuit does not blurhelper exists,helper bound into statement truth, andaccepted statement now deserves authorityinto one vague feeling that validation happened somewhere. - The cleanest shape is
instantiate validator, constrain success immediately. When a helper exists only to expose a boolean, the safest call pattern is often one line later:validator.out === 1. - Validation-heavy circuits should make omission difficult by API design. Helpers for mandatory invariants can be written to fail closed internally or return no success bit at all, leaving no caller discretion about whether the check matters.
- Reviewers should be able to answer a concrete question for every helper:
where exactly does this result become part of the proved statement?If the answer is vague, the check likely is not real yet. - Healthy systems treat
validation wiringas proof-authority logic. Missing one equality on a helper output can be as dangerous as omitting a withdrawal authorization check in ordinary Solidity. - High-signal incidents:
- [[../../../incidents/proofs-verifiers/circom-pairing-coreverifypubkeyg1-biglessthan-output-omission-forged-signature-near-miss-2022-11-25|circom-pairing
CoreVerifyPubkeyG1()BigLessThanoutput omission / forged-signature near miss (2022-11-25)]] — the clean current exemplar: tenBigLessThanvalidators were instantiated to keep BLS12-381 coordinates belowqand properly formatted, but none of their success bits were asserted, so the outer signature-verification relation silently dropped the intended admission check. The primary artifact worth re-reading is tiny and brutally clear: PR #21 adds a six-liner += lt[i].out; r === 10;aggregate that finally turns those ten advisory outputs into live statement truth.
- [[../../../incidents/proofs-verifiers/circom-pairing-coreverifypubkeyg1-biglessthan-output-omission-forged-signature-near-miss-2022-11-25|circom-pairing
Failure-prevention checklist
- Inventory every helper gadget that returns a success bit, acceptance flag, comparison result, or validation summary, and mark whether it is advisory or mandatory. Mandatory ones must be tied to an explicit equality in the proved statement.
- For every call site that instantiates a mandatory validator, add the enforcing constraint immediately after wiring inputs unless the helper itself already fails closed internally.
- Prefer helper APIs that encode mandatory checks as no-choice assertions rather than optional booleans. If a caller should never ignore a result, do not make
ignore resultan easy API outcome. - Add regression tests that attempt proof generation with invalid coordinates, malformed bigints, bad parser states, or illegal selectors. The expected result should be proof failure, not a computed
0in some unconstrained debug lane. - Review comments and docs that say
check,verify,validate, orensureagainst the actual constraint graph. Naming is not evidence. - When aggregating multiple validation results, constrain the final count or conjunction explicitly and keep the expected value obvious in code review.
- Treat helper outputs as part of the statement schema during audits. The question is not only
what are the public inputs and witnesses?but alsowhich validator outputs must be fixed for the statement to mean what the team thinks it means? - Separate the three promotions explicitly in review notes:
validator exists,validator success became statement truth, andthat accepted statement now carries bridge / signature / identity / payout authority. The dangerous bug often lives in the second promotion even when teams keep talking only about the first and third. - Re-run malformed-input regression suites after optimization passes, helper refactors, or inlining changes. This bug family often appears when teams separate performance work from security review.
- Keep one negative corpus for each validator family — range, subgroup, parser, selector, formatting — so future circuits cannot quietly reintroduce the same omission under different names.
- During audits, ask for one machine-readable or reviewer-readable map from validator outputs to final enforcing constraints. If that map does not exist, omission bugs are likely hiding in the gap.
Audit prompts
- Which helper gadgets return a boolean or summary output rather than enforcing their own validity internally?
- For each such gadget, where is the exact constraint that requires success instead of merely computing it?
- Can I generate a proof with an input that should fail validation but still satisfies the rest of the circuit because the validator output is unconstrained?
- Do any comments, audit notes, or code structure imply a check happened even though the corresponding success bit never reaches a hard equality?
- If several validation outputs are summed or combined, what final assertion proves the aggregate actually had to pass?
- Are there helper gadgets whose internal normalization work makes reviewers feel safe even though the decisive comparison or acceptance condition is optional?
- Could a malformed value stay outside the intended field, subgroup, parser language, or selector set and still influence downstream arithmetic or authority?
- Which negative tests prove
invalid input => proof failureinstead of merelyinvalid input => validator outputs 0 somewhere? - After optimization or modularization, who verifies that validation outputs are still consumed by the live statement rather than left as dead side computations?
- If a verifier accepted one surprising proof today, which validator output would you inspect first to confirm the circuit actually required success there?
Lessons that should already be standard
- In a zk circuit, computed is not enforced. A validator output that never reaches a hard constraint is the proof-equivalent of a warning log, not a security control.
Validator exists,statement proves validator passed, andaccepted proof now deserves real authorityare three different promotions. This family is exactly the bug where reviewers subconsciously jump from the first straight to the third.- Reusable helper gadgets create a dangerous review illusion: code can look validation-heavy while the actual proved statement omits the last inch that makes the validation matter.
- One missing
=== 1can be a soundness bug, not a style nit. Teams used to ordinary programming often underestimate how much security sits in these tiny statement-binding edges. - Negative proofs matter more than positive tests for this family. Ordinary happy-path proving often looks fine because the validator does compute the right answer; the exploit appears only when invalid input still proves.
- Validation outputs are part of the protocol’s security object. Audits should map them with the same seriousness given to public inputs, nullifiers, and withdrawal conditions.
- Performance-driven modularity often increases this risk. The more a circuit factors validation into helper templates, the easier it becomes to instantiate checks without actually consuming them.
- The clean mantra is simple: if the system must rely on a validation result, that result must be forced into the proved statement immediately and visibly.
Where this pattern stops
- Use public-input-domain-mismatch when the decisive failure is that the contract and verifier disagree about the numeric domain of one proof-facing value even though the verifier-side checks are real.
- Use witness-public-input-binding-failure when the proof statement splits one semantic fact across unconstrained public-input and witness-side roles rather than merely forgetting to consume a validator output.
- Use curve-point-validation-failure when malformed proof elements survive a parser or verifier admission boundary into arithmetic or payout logic; that family preserves the broader malformed-element story, while this note preserves the narrower
the validation gadget existed, but its success bit never became statement truthsubfamily. - In short: this pattern begins once the circuit computes a security-critical validation result without actually requiring that result to hold, and it stops once the sharper story is instead contract/verifier domain drift, split-statement soundness, or malformed-proof admission at a different boundary.
Internal linkages
- Best current incident exemplar: circom-pairing-coreverifypubkeyg1-biglessthan-output-omission-forged-signature-near-miss-2022-11-25.
- Positive-design companion: proof-validation-output-consumption-and-statement-binding-discipline — the sharper healthy-side question of how mandatory validator outputs should become explicit statement truth instead of dead side computation.
- Broader malformed-element companion: proof-element-admission-boundary-discipline — useful when the healthier-side question widens from
did we consume the validator output?towhere should malformed proof-facing objects die before arithmetic or authority begins? - Adjacent field-domain companion: proof-facing-field-domain-canonicalization-discipline — useful when the missing check concerns keeping contract-facing values inside the proving field end to end rather than consuming an already-instantiated validator output.
- Adjacent malformed-element family: curve-point-validation-failure.
- Adjacent split-statement family: witness-public-input-binding-failure.
Control surface
-
The leverage sits in helper-gadget APIs, the exact lines that bind
outsignals into the statement, and every optimized or modularized circuit boundary where reviewers may mistakevalidator instantiatedforvalidator enforced. -
The recurring mistake is small but deadly: a circuit computes the right security answer and then proves a statement that never actually depends on that answer.
-
The control surface is therefore a promotion ladder, not one moment: helper existence, promotion of helper output into canonical statement truth, and the later decision to let that accepted statement inherit signature, bridge, identity, or settlement authority.
-
Sources:
- https://github.com/yi-sun/circom-pairing/pull/21
- https://patch-diff.githubusercontent.com/raw/yi-sun/circom-pairing/pull/21.patch
- https://raw.githubusercontent.com/yi-sun/circom-pairing/c686f0011f8d18e0c11bd87e0a109e9478eb9e61/circuits/bls_signature.circom
- https://medium.com/veridise/circom-pairing-a-million-dollar-zk-bug-caught-early-c5624b278f25
- https://github.com/0xPARC/zk-bug-tracker
-
Last reviewed: 2026-08-01 UTC