Submitted by m9800, also found by ladboy233
A user can use the same commitment signature and merkleData more than 1 time to obtain another loan.
A user needs to make some procedures to take a loan against an NFT.
Normally the user calls commitToLiens() in AstariaRouter.sol providing IAstariaRouter.Commitment[] as input.
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/AstariaRouter.sol#L490
The function will transfer the NFT to the CollateralToken contract to get a collateral id for the user (see CollateralToken.onERC721Received() ).
After that, the function in the router will make an internal call _executeCommitment() for each commitment.
_executeCommitment() checks the collateral id and the commitment.lienRequest.strategy.vault and then calls commitToLien in
commitment.lienRequest.strategy.vault with the commitment and the router address as the receiver (ie: address (this)).
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/AstariaRouter.sol#L761
_executeCommitment() in AstariaRouter.sol
commitToLien() function in VaultImplementation:
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L287
The function in the Vault will among other things request a lien position and issue the payout to the user requesting the loan via
_requestLienAndIssuePayout().
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L379
This function validates the commitment with the signature against the address of the owner of the vault or the delegate.
To recover the address with ecrecover an auxiliary function is used to encode the strategy data (_encodeStrategyData() ) but the strategy.vault is not being taken into account in the bytes returned nor the strategy version.
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L229
So _validateCommitment will not revert if I use it with little changes in the Commitment like strategy.vault because there are not going to be changes in _encodeStrategyData().
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L178
We saw that the user started the operation in Router but he could have called directly commitToLien in the vault after manually transferring the NFT to Collateral.sol and obtaining the collateral token. Then strategy.vault and strategy.version can be changed by the user breaking the invariant  commitment.strategy.vault == vault where commitToLiens() is being called and the vault will not notice it and will consider the signature of the commitment as valid.
So the procedure will be the following:
Theres one more check of the commitment to verify: the StrategyValidator one with the nlrDetails and the merkle. This is done in the Router contract by _validateCommitment().
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/AstariaRouter.sol#L434
This will call validateAndParse on the validators contract (address strategyValidator = s.strategyValidators[nlrType];).
This validation and parse will depend on the validator but we have examples like UNI_V3Validator.sol
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/strategies/UNI_V3Validator.sol#L80
This function makes some checks but if those checks passed the first time they will pass the second because the changes done
(strategy.vault and stack) are not checked here.
The leaf returned is leaf = keccak256(params.nlrDetails), and it will be checked against the root and the proof.
A portion of code of _validateCommitment in AstariaRouter:
You can add a nonce for the user and increment it each time he takes a loan.
androolloyd (Astaria) disputed via duplicate issue #140 and commented:
Picodes (judge) commented via duplicate issue #140:
