Skip to content
This repository has been archived by the owner on Jan 7, 2024. It is now read-only.

xiaoming90 - Lack of signature expiration within the verifyPrices and verifyQuotePrices functions #235

Closed
sherlock-admin opened this issue Jul 3, 2023 · 0 comments
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A valid High severity issue Reward A payout will be made for this issue

Comments

@sherlock-admin
Copy link
Contributor

sherlock-admin commented Jul 3, 2023

xiaoming90

high

Lack of signature expiration within the verifyPrices and verifyQuotePrices functions

Summary

The lack of signature expiration within the verifyPrices and verifyQuotePrices functions could allow malicious users to use a price signature generated a long time ago (e.g. 1 month ago, 6 months ago) where its symbol prices have already deviated significantly from the current market price to exploit the price differences to extract values/assets from the protocol or its victims.

Vulnerability Detail

The verifyPrices and verifyQuotePrices functions do not verify that the price signature has been generated recently. As a result, a price signature generated a long time ago (e.g. 1 month ago) will still pass the verification.

https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibMuon.sol#L50

File: LibMuon.sol
50:     function verifyPrices(PriceSig memory priceSig, address partyA) internal view {
51:         MuonStorage.Layout storage muonLayout = MuonStorage.layout();
52:         require(priceSig.prices.length == priceSig.symbolIds.length, "LibMuon: Invalid length");
53:         bytes32 hash = keccak256(
54:             abi.encodePacked(
55:                 muonLayout.muonAppId,
56:                 priceSig.reqId,
57:                 address(this),
58:                 partyA,
59:                 priceSig.upnl,
60:                 priceSig.totalUnrealizedLoss,
61:                 priceSig.symbolIds,
62:                 priceSig.prices,
63:                 priceSig.timestamp,
64:                 getChainId()
65:             )
66:         );
67:         verifyTSSAndGateway(hash, priceSig.sigs, priceSig.gatewaySignature);
68:     }

https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibMuon.sol#L70

File: LibMuon.sol
70:     function verifyQuotePrices(QuotePriceSig memory priceSig) internal view {
71:         MuonStorage.Layout storage muonLayout = MuonStorage.layout();
72:         require(priceSig.prices.length == priceSig.quoteIds.length, "LibMuon: Invalid length");
73:         bytes32 hash = keccak256(
74:             abi.encodePacked(
75:                 muonLayout.muonAppId,
76:                 priceSig.reqId,
77:                 address(this),
78:                 priceSig.quoteIds,
79:                 priceSig.prices,
80:                 priceSig.timestamp,
81:                 getChainId()
82:             )
83:         );
84:         verifyTSSAndGateway(hash, priceSig.sigs, priceSig.gatewaySignature);
85:     }

Impact

Without any signature expiration mechanism, the old price signatures where their symbol prices have already deviated significantly from the current market price could be injected into the protocol. Malicious users could potentially exploit the price differences to extract values/assets from the protocol or its victims.

Code Snippet

https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibMuon.sol#L50

https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibMuon.sol#L70

Tool used

Manual Review

Recommendation

Define the muonLayout.priceValidTime timeout and implement the following validation check within the affected functions to ensure that only price signatures generated recently are accepted.

function verifyPrices(PriceSig memory priceSig, address partyA) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(priceSig.prices.length == priceSig.symbolIds.length, "LibMuon: Invalid length");
+    require(
+        block.timestamp <= priceSig.timestamp + muonLayout.priceValidTime,
+        "LibMuon: Expired signature"
+    );
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            priceSig.reqId,
            address(this),
            partyA,
            priceSig.upnl,
            priceSig.totalUnrealizedLoss,
            priceSig.symbolIds,
            priceSig.prices,
            priceSig.timestamp,
            getChainId()
        )
    );
    verifyTSSAndGateway(hash, priceSig.sigs, priceSig.gatewaySignature);
}

function verifyQuotePrices(QuotePriceSig memory priceSig) internal view {
    MuonStorage.Layout storage muonLayout = MuonStorage.layout();
    require(priceSig.prices.length == priceSig.quoteIds.length, "LibMuon: Invalid length");
+    require(
+        block.timestamp <= priceSig.timestamp + muonLayout.priceValidTime,
+        "LibMuon: Expired signature"
+    );
    bytes32 hash = keccak256(
        abi.encodePacked(
            muonLayout.muonAppId,
            priceSig.reqId,
            address(this),
            priceSig.quoteIds,
            priceSig.prices,
            priceSig.timestamp,
            getChainId()
        )
    );
    verifyTSSAndGateway(hash, priceSig.sigs, priceSig.gatewaySignature);
}

Duplicate of #113

@github-actions github-actions bot added High A valid High severity issue Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label labels Jul 10, 2023
@sherlock-admin2 sherlock-admin2 added the Reward A payout will be made for this issue label Jul 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A valid High severity issue Reward A payout will be made for this issue
Projects
None yet
Development

No branches or pull requests

2 participants