# Signed or negative input bypasses guard

Negative or zero values reaching guards, offsets, timestamps or arithmetic without sign or bound checks

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2025-08-21. Updated 2026-10-25._

## How it works
A guard or arithmetic constructor assumes its input is a non-negative, in-range number. Nothing enforces that assumption. A signed or negative value then either slips past a comparison (because the check was written for the positive domain) or makes a downstream assertion revert, disabling the path that was supposed to enforce a rule. The broken assumption is "this value is a valid amount/offset/timestamp"; the code never proves it.

## Where it shows up
- Config setters that accept a delay, offset, expiry or percentage with no minimum or sign check [E2](https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.3.6.md).
- Hand-built calldata or offset/length arithmetic using raw `add` instead of checked math, with no equality check against the expected layout [E1](https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-07.md).
- Assertions (e.g. absolute-time checks) that revert on negative signed integers, turning a bad value into a denial of the enforcement path [E2](https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.3.6.md).
- Setters that treat `0` as "uninitialized" and overwrite a deliberate zero with a default [E3](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-12.md).
- Any value flowing from user/operator input into a comparison, timestamp, or ABI offset without a bound.

## How to review
For each input that reaches a guard, offset, timestamp or arithmetic constructor, state the invariant: the value is within `[min, max]` and non-negative before use. Check that the setter or encoder enforces it explicitly, not implicitly via a comparison that only holds for positives. For hand-built calldata, verify every offset equals the expected pointer plus fixed size and that all offset/length math is checked [E1](https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-07.md). For timestamps, confirm the assertion cannot be driven negative [E2](https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.3.6.md). For config, confirm `0` is not overloaded as a sentinel where it is also a valid setting [E3](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-12.md).

## Variants seen
- Missing offset equality check plus unsafe arithmetic in bootloader calldata encoding [E1](https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-07.md).
- Negative delay making an expiry timestamp negative, so the penalty assertion reverts [E2](https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.3.6.md).
- Zero conflated with uninitialized, re-init resets a deliberate lock to a default [E3](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-12.md).

## Impact and severity
Led to operator-injected calldata or forced reverts in a bootloader [E1](https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-07.md), announcers becoming unpenalizable (enforcement DoS) [E2](https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.3.6.md), and unauthorized selling of tokens meant to be locked [E3](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-12.md). Severity rises when the bypassed guard protects funds, penalties, or lock guarantees, and when the bad value persists in stored config.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-07.md
- E2: https://bugbountylibrary.com/r/cantina%3Acircuit_puzzles%3A3.3.6.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-12.md
