Quantstamp reviewed Alchemy ERC (Alchemy - LightAccount v2) on 9 Apr 2024: 4 findings, 0 critical; 3 marked fixed, 1 open.
Report hosted on certificate.quantstamp.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 0 |
| Medium | 0 | 0 | 0 |
| Low | 1 | 0 | 3 |
When an EOA signature is submitted, it is decoded via `digest.tryRecover(signature)`. This function call returns the address recovered and an error of type `ECDSA.RecoverError`. There are currently 4 entries in the `ECDSA.RecoverError` enum: ``` 1. NoError, 2. InvalidSignature, 3. InvalidSignatureLength, 4. InvalidSignatureS ``` In the current iteration of the code base, in the case of the 3 invalid errors, `SIG_VALIDATION_FAILED` is returned, which is not entirely correct, as it should only be returned if a signature is correctly formed but the validation fails. The only case where `SIG_VALIDATION_FAILED` should be returned is `NoError`, but the signer does not match the expected `owner`, which means that the signature is correctly formed, but the validation fails. In the case of `InvalidSignatureLength`, `InvalidSignatureS` and `InvalidSignature`, the signature itself is invalid; in the first case, the signature is not of length `65`. In the second error, the `s` value is in the upper range, and in the last error, either `r = 0`, `s = 0`, or `r` is too large.
It is important to validate inputs, even if they only come from trusted addresses, to avoid human error. Specifically, in the following functions: 1. `BaseLightAccount.withdrawDepositTo()` should check that `withdrawAddress` is not `address(0) `. 2. `BaseLightAccountFactory.withdrawStake()` should check that `to` is not `address(0) `. 3. `BaseLightAccountFactory.withdraw()` should check that `to` is not `address(0) `.
The `_validateSignature()` function of `MultiOwnerLightAccount` allows the user operation to be validated in three different modes based on the first byte of `userOp.signature`. The mode `SignatureType.CONTRACT` iterates through the owner list until it finds an owner contract accepting the given signature. On the other hand, the mode `SignatureType.CONTRACT_WITH_ADDR` only checks if one owner contract accepts the signature, which provides potential gas savings as the iteration through the owner list is avoided. However, an adversary who listens to the user operation requests, such as a bundler, can modify the first byte of `userOp.signature` and force the account to use a more gas-expensive signature validation mode by switching from `CONTRACT_WITH_ADDR` to `CONTRACT`. If the specified verification gas limit in the user operation is sufficiently high, the signature validation can still pass since the only-provided signature is correct. Note that the user operation signer is usually not incentivized to set an overly high verification gas limit. Also, the incentive for an adversary to perform such an attack seems low since they do not directly gain profit. Due to the above reasons, this issue is considered Info severity.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (77)
236 projects reviewed · 332 reports · latest Oct 2026
See Quantstamp’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us