Organization
- @coinbase
Engagement Type
Cantina Reviews
Period
-
Repositories
Findings
Informational
3 findings
1 fixed
2 acknowledged
Informational3 findings
Missing event for signer rotations
State
- Acknowledged
Severity
- Severity: Informational
Submitted by
r0bert
Description
The
SignatureDiscountValidator.setSignerfunction mutates the signer without emitting an event and the constructor also initializes the signer silently. Off-chain services (discount portals, caching layers, monitoring dashboards) cannot detect signer rotations or invalidate cached signatures promptly without polling storage directly, which both increases operational risk and delays revocations.Recommendation
Declare
event SignerUpdated(address indexed oldSigner, address indexed newSigner);and emit it in the constructor andsetSigner, passing the previous value so downstream systems can react to signer rotations.Coinbase: Acknowledged. Won't fix as we're expecting this to be used rarely (~1/yr maximally). Additionally we wouldn't expect to listen to this event since we would be the party executing the change in the first place. We can't come up with an external party that would care to listen to this event.
Incorrect NatSpec Comment for Signature Expiration Boundary Condition
State
Severity
- Severity: Informational
Submitted by
r0bert
Description
SybilResistanceVerifier.verifySignaturetreats a signature as valid when the packedexpiresequals the current block timestamp because it only reverts whenexpires < block.timestamp.if (expires < block.timestamp) revert SignatureExpired();On the flipside, the NatSpec comment for
SignatureExpiredstates, “Thrown when the signature expiry date >= block.timestamp,”:/// @notice Thrown when the signature expiry date >= block.timestamp. error SignatureExpired();implying equality should already be rejected. The NatSpec is wrong as signatures should still be valid when their expiry date is equal to
block.timestamp.The mismatch between documentation and behavior risks engineers relying on the wrong edge condition.
Recommendation
Update the NatSpec to reference only an expired signature when
block.timestampis bigger than the expiry date:- /// @notice Thrown when the signature expiry date >= block.timestamp.+ /// @notice Thrown when the signature expiry date < block.timestamp.Coinbase: Fixed in 791f5a0.
Cantina: Fix verified.
Discount signatures scoped per validator instance
State
- Acknowledged
Severity
- Severity: Informational
Submitted by
r0bert
Description
SignatureDiscountValidator.isValidDiscountRegistrationverifies only(claimer, expires, signature)and does not receive thediscountKeybeing claimed. In theory, if multiple discount keys were mapped to the same validator, one signed authorization could be replayed across tiers because the signature payload omits the specific key. However, the deployment plan explicitly assigns a singlediscountKeyper validator/signer pair, so there is no path for a signature to “jump” to a different tier. Under that operational constraint the previously identified risk is not exploitable and should be treated as informational documentation of the coupling assumption instead of an active issue.Recommendation
Maintain (and ideally enforce in configuration/tests) the invariant that each validator instance serves exactly one
discountKey. If future requirements ever call for multiple tiers behind the same validator, revisit this design and include the key or equivalent salt inside the signed payload to prevent cross-tier reuse.Coinbase: Acknowledged. This is known and each validator will be ever assigned a single
discountKey.