The LibTracker Faucet uses C.sol
contract in which legacy chainId and chainId variables are declared which are used inside Libtracker when determining chainId for the calculation of domain Separator . However , the ChainId is not determined by block.chainId rather hardcoded which exposes blueprints to be re-used across different forks of eth mainnet in the event of chain fork. This breaks the core part of the system assumption that one signature should be used only once which is valid.
Inside TrackerFaucet.sol
, the modifier verifyRequisition
uses LibTractor._getBlueprintHash
to determine the blue print hash.
and check if the blue print publisher is infact the one who has signed it .
this is used across publishRequisition
and cancelBluePrint
methods to ensure authenticity of blueprints.
The LibTractor._getBlueprintHash
is defined as follows
the method _hashTypedDataV4
is defined as
if we check following line C.getChainId(),
, this line , According to EIP712 (uint256 chainId the EIP-155 chain id. The user-agent should refuse signing if it does not match the currently active chain.
)
intends to fetch the chain id of the current active chain.
However , if we look at C.getChainId(),
method ,
This is just returning the hardcoded value uint256 private constant CHAIN_ID = 1;
.
If a fork of Ethereum is
made after the contract’s creation, every blue print will be usable in both forks.
Bob has submitted a signature blueprint to perform some beanstalk operation and allows Eve to do it ( let's say beanstalk allows operator and owner paradigm for managing some operations involving tokens ) using that blueprint . And imagine something catastrophic happens or ethereum community wants to introduce a big change,
let's name it London fork. When the London hard fork is executed, a subset of
the community declines to implement the upgrade. As a result, there are two parallel
chains with the same chainID value as 1 because it was hardcoded , and Eve can use Bob’s signature to transfer funds on both
chains because the domain separator does not use fresh block.chainId
in its calculation.
Signature Replay of BluePrints across chains
Manual Review
Use block.chainId
to determine the currently active chainId. This also adheres to EIP712's description of chainId param.
Check a similar finding by some fellows at ToB
https://solodit.xyz/issues/risk-of-reuse-of-signatures-across-forks-due-to-lack-of-chainid-validation-trailofbits-looksrare-pdf
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.