BUG BOUNTYFIELD MANUAL
Reusable module
Markdown
0 / 5 checkedChecks last until this page reloads.

Contract signatures and oracles: context, freshness and units

Test signed-action context and price-consumer assumptions with local keys, mock feeds and explicit negative controls.

Investigation sequence
  1. 01Record trust contract
  2. 02Prove valid baseline
  3. 03Vary one binding
  4. 04Vary feed metadata
  5. 05Calculate consequence

At each step: retain the control → record the observation → continue only while the next boundary is understood.

Used in these playbooks#

Setup and invariants#

Create two locally deployed verifier instances, a local-only signer, two ordinary actors and a mock feed whose state you can vary. Write the expected signed action as a tuple: signer, action type, recipient, amount, nonce, deadline, chain and verifying contract. Record which fields the application intentionally binds. The invariant is: a signed instruction permits only its intended action and replay policy. EIP-712 defines typed hashing and domain separation; replay protection remains the application's responsibility. EIP-712

For price consumers, record base/quote currency, feed decimals, token decimals, supported price range, freshness policy and dependency-failure behavior. The invariant is: an accepted observation has the meaning and validity required for the resulting economic decision. Chainlink exposes round metadata and timestamps; consumers must interpret them in their own integration. Chainlink data-feed API

Controlled procedure#

  1. Prove both baselines. A valid local signature executes its harmless ledger action once. A fresh positive-price feed produces the expected collateral or quote calculation. Verify an invalid signature and an explicitly disallowed stale observation are rejected, where that policy is part of the product's contract.
  2. Vary one signature dimension. After the valid action, replay exactly the same bytes. Then use fresh baselines to vary only the recipient, amount, action type, verifier instance, chain context or expired timestamp. Record the recovered signer and nonce-consumption point. A reverting transaction normally rolls back its state; prove whether the replay state survives a successful action rather than assuming a pre-revert write consumed the nonce.
  3. Check alternate signer paths. If contract wallets are supported, compare an owned wallet returning the ERC-1271 success value 0x1626ba7e, a wallet returning a different value, and a reverting wallet. A non-reverting call alone does not establish a valid signature. ERC-1271 validity can depend on current contract state: change the authorized local signer after a valid baseline and repeat only where the consumer promises current authorization. Record validation at execution versus an intentionally earlier irrevocable authorization. Do not classify unsupported signature formats as a vulnerability. Reuse identity and session binding for off-chain issuance. ERC-1271.
  4. Vary feed metadata. Starting from a valid response, test an old timestamp, zero or negative answer where the feed type can produce it, changed decimals, failed feed call and mismatched quote currency. Keep all other fields realistic. Demonstrate the consumer's accepted result and economic effect; an artificial impossible feed response is a robustness result until reachable conditions are shown.
  5. Test L2 recovery if applicable. Model sequencer down, just restarted and beyond the configured grace period separately. This is integration-specific: not every chain or feed uses identical checks. Chainlink's L2 guidance explains uptime signals and post-recovery grace periods. L2 sequencer feeds
  6. Calculate the consequence. Compare collateral, debt, quote or liquidation outcome with an independently calculated expectation. Include price units, rounding, capital, timing, fees and user constraints. A missing named check without a reachable incorrect decision remains a review lead.

Local cheat sheet and case matrix#

Implement these names in your reviewed local Foundry harness; they are not scanner features. The signer key must be generated or hard-coded solely for this disposable local fixture.

rg -n 'ecrecover|nonces|deadline|DOMAIN_SEPARATOR|latestRoundData|decimals' src
forge test --match-test '^test_ValidSignature$' -vvvv
forge test --match-test '^test_ReplayRejected$' -vvvv
forge test --match-test '^test_WrongDomainRejected$' -vvvv
forge test --match-test '^test_StaleFeedRejected$' -vvvv
forge test --match-test '^test_PriceUnitInvariant$' -vvvv

--match-test selects target-specific tests and trace verbosity helps identify the accepted transition. Use preinstalled compiler/dependencies and no RPC/fork/FFI setup for these local fixtures. Foundry test reference

Comparison Hold constant Vary
Replay Signature, actor, verifier Prior successful consumption
Domain Message and signature Local verifier or chain context
Freshness Price and units Observation timestamp
Unit conversion Economic value Supported decimal representation

Evidence and checklist#

  • Exact message schema, domain and successful baseline are saved.
  • Only one context field changes in each negative case.
  • Mock feed deviations are separated from reachable attacker powers.
  • Nonces, timestamps, units and downstream decisions appear in evidence.
  • No real signatures, transactions or funds are used.

Vulnerability reverse references#

Nearby shared procedures#

Object, function, and property authorization · Authentication, recovery, federation, and session lifecycle · Trace input into queries, commands, and templates · Server-side fetching and network trust boundaries · Browser execution, cross-origin reads, and forged actions · Uploads, downloads, paths, archives, and XML · Workflow invariants, replay, idempotency, and races · REST, GraphQL, gRPC, WebSocket, and SSE permission parity