# Unconstrained signature scalar and domain

ecrecover bounds, forwarder allowlists, optional flags that skip signature validation

_Area: Smart contract access control and control flow. Seen in 3 disclosed reports; one confirmed bounty: $400,000; latest 2025-11-21. Updated 2026-10-31._

## How it works
Signature verification rests on three assumptions: the scalar `s` is within the valid secp256k1 range, the signer/forwarder is one you trust, and any optional validation flag is actually enforced. When one of these is silently dropped, a signature that should be rejected is accepted. The root cause is a missing constraint, not broken crypto: a check that is overridden, conditional, or never applied.

## Where it shows up
- `ecrecover` wrappers or precompiles that do not reject `s > secp256k1n` [E3](https://bugbountylibrary.com/r/c4%3A2024-09-kakarot%3AH-06.md)
- Meta-transaction paymasters whose `preRelayedCall` does not compare the supplied forwarder against a trusted allowlist [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-enzyme-finance-privilege-check.md)
- Signature libraries where a validation step (checkpointer, snapshot) is gated on an optional bit or flag [E2](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-01.md)
- Inherited/overridden functions that replace a function containing a security check [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-enzyme-finance-privilege-check.md)
- Chained or nested signatures where inner data is recovered with validation disabled [E2](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-01.md)

## How to review
State the invariant: every accepted signature must come from a trusted signer under a trusted domain, and `s` must be canonical. Trace each path to `ecrecover`/recovery and confirm:
- `s` is bounded to the valid secp256k1 range, and out-of-range inputs produce the same result as canonical Ethereum (e.g. `address(0)`) [E3](https://bugbountylibrary.com/r/c4%3A2024-09-kakarot%3AH-06.md)
- The forwarder/domain is checked against an allowlist on every relay path, including overrides [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-enzyme-finance-privilege-check.md)
- Optional flags default to *enabling* validation, not skipping it; unset bits must not zero out checkpointer data [E2](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-01.md)
Differential-test edge inputs (out-of-range `s`) against canonical behavior [E3](https://bugbountylibrary.com/r/c4%3A2024-09-kakarot%3AH-06.md).

## Variants seen
- Missing forwarder allowlist in an overridden paymaster function [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-enzyme-finance-privilege-check.md)
- Optional checkpointer flag unset in a chained signature skips validation [E2](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-01.md)
- Unbounded `s` yields a third valid signature for one message [E3](https://bugbountylibrary.com/r/c4%3A2024-09-kakarot%3AH-06.md)

## Impact and severity
Led to vault drain via inflated relay fees [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-enzyme-finance-privilege-check.md), evicted-signer authorization with stale config [E2](https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-01.md), and broken signature-uniqueness assumptions [E3](https://bugbountylibrary.com/r/c4%3A2024-09-kakarot%3AH-06.md). Severity is high when the bypass reaches fund movement or authorization; worse when the flaw sits in a shared library or precompile reached by many callers.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-enzyme-finance-privilege-check.md
- E2: https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AH-01.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-09-kakarot%3AH-06.md
