code-423n4 / 2024-03-ondo-finance-findings

5 stars 6 forks source link

Insufficient safeguards for handling price data in `ROUSG::getOUSGPrice` may lead to arithmetic underflow or overflow error #144

Closed c4-bot-8 closed 6 months ago

c4-bot-8 commented 6 months ago

Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/rOUSG.sol#L378

Vulnerability details

Impact

A price oracle delivers up-to-date price information, enabling smart contracts to engage with real-world data. This functionality supports automated trading of assets like shares and swaps. When incorporating price oracles into smart contracts, it’s crucial to implement protective measures to ensure the security and reliability of the data received.

The ROUSG::getOUSGPrice function retrieves price data for OUSG tokens from IRWAOracle. This data includes both the price and timestamp. The function directly utilizes the price data from the oracle without any additional validation or checks. Subsequently, the OUSG price is directly used as input for four other functions namely ROUSG::balanceOf, ROUSG::totalSupply, ROUSG::getSharesByROUSG, and ROUSG::getROUSGByShares. As such, the following safeguards have not been implemented in ROUSG::getOUSGPrice (and also IRWAOracle::getPriceData):

Our tests noted unvalidated price data caused “panic: arithmetic underflow or overflow” error, and impacted the processing of ROUSG::BalanceOf function.

Proof of Concept

We added 2 Foundry tests into rOUSG.t.sol to demonstrate the issue of unvalidated price data and its impact on the ROUSG::BalanceOf function. Each of the 2 Foundry tests used a different value as price data. There was a normal value of $1 and an exceptionally large number of $2**255-1.

For the test_unvalidated_pricedata() Foundry test, the price data used was the normal value of $1. It was a successful test. The price data did not negatively impact the processing of the ROUSG::BalanceOf function.

For the testFail_unvalidated_pricedata Foundry test, the price data was set to the maximum positive int256 value (i.e. $2**255-1). It was a successful testFail. Unlike the previous Foundry test, this test showed that price data impacted the processing of ROUSG::BalanceOf function. Refer to the detailed output for the failed test due to “panic: arithmetic underflow or overflow” error.

To perform the tests:


* Navigate to the forge-tests directory at the terminal, replace the <replace with MAINNET_RPC_URL>  and run the following Foundry test commands:

```javascript
forge test --fork-url <replace with MAINNET_RPC_URL>  --nmc ASSERT_FORK --mt test_unvalidated_pricedata -vvvv 

forge test --fork-url <replace with MAINNET_RPC_URL>  --nmc ASSERT_FORK --mt testFail_unvalidated_pricedata -vvvv

Below are the Foundry test results for reference.

Detailed test results: test_unvalidated_pricedata successful (normal value of $1)

[⠒] Compiling...
[⠒] Compiling 168 files with 0.8.16
[⠆] Solc 0.8.16 finished in 10.40s
Compiler run successful with warnings:
Warning (3420): Source file does not specify required compiler version! Consider adding "pragma solidity ^0.8.16;"
--> forge-tests/ousg/OUSGInstantManager/buidl_helper.sol

Warning (2072): Unused local variable.
   --> forge-tests/ousg/OUSGInstantManager/usdc_buffer.t.sol:217:5:
    |
217 |     uint256 usdcAmount = 225_000e6;
    |     ^^^^^^^^^^^^^^^^^^

Warning (2072): Unused local variable.
  --> forge-tests/rwaOracles/RWAOracleRateCheck.t.sol:36:5:
   |
36 |     RWAOracleRateCheck badSetter = new RWAOracleRateCheck(
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ran 1 test for forge-tests/ousg/rOUSG.t.sol:Test_rOUSG_ETH
[PASS] test_unvalidated_pricedata() (gas: 222667)
Logs:
  ROUSG deployed 0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A
  OUSG Instant Manager deployed 0xa0Cb889707d426A7A386870A03bc70d1b0697598

Traces:
  [226880] Test_rOUSG_ETH::test_unvalidated_pricedata()
    ├─ [0] VM::prank(0xAEd4caF2E535D964165B4392342F71bac77e8367)
    │   └─ ← [Return] 
    ├─ [64185] TokenProxy::mint(0x0000000000000000000000000000000009999991, 1000000000000000000 [1e18])
    │   ├─ [56887] CashKYCSenderReceiver::mint(0x0000000000000000000000000000000009999991, 1000000000000000000 [1e18]) [delegatecall]
    │   │   ├─ [8528] KYCRegistry::getKYCStatus(1, 0xAEd4caF2E535D964165B4392342F71bac77e8367) [staticcall]
    │   │   │   ├─ [2923] SanctionsList::isSanctioned(0xAEd4caF2E535D964165B4392342F71bac77e8367) [staticcall]
    │   │   │   │   └─ ← [Return] false
    │   │   │   └─ ← [Return] true
    │   │   ├─ [6028] KYCRegistry::getKYCStatus(1, 0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   ├─ [2923] SanctionsList::isSanctioned(0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   └─ ← [Return] false
    │   │   │   └─ ← [Return] true
    │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000009999991, value: 1000000000000000000 [1e18])
    │   │   └─ ← [Stop] 
    │   └─ ← [Return] 
    ├─ [0] VM::startPrank(0x0000000000000000000000000000000009999991)
    │   └─ ← [Return] 
    ├─ [25492] TokenProxy::approve(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], 1000000000000000000 [1e18])
    │   ├─ [24691] CashKYCSenderReceiver::approve(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], 1000000000000000000 [1e18]) [delegatecall]
    │   │   ├─ emit Approval(owner: 0x0000000000000000000000000000000009999991, spender: TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], value: 1000000000000000000 [1e18])
    │   │   └─ ← [Return] true
    │   └─ ← [Return] true
    ├─ [116957] TokenProxy::wrap(1000000000000000000 [1e18])
    │   ├─ [109662] ROUSG::wrap(1000000000000000000 [1e18]) [delegatecall]
    │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, 0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   ├─ [923] SanctionsList::isSanctioned(0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   └─ ← [Return] false
    │   │   │   └─ ← [Return] true
    │   │   ├─ [41225] TokenProxy::transferFrom(0x0000000000000000000000000000000009999991, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], 1000000000000000000 [1e18])
    │   │   │   ├─ [40418] CashKYCSenderReceiver::transferFrom(0x0000000000000000000000000000000009999991, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], 1000000000000000000 [1e18]) [delegatecall]
    │   │   │   │   ├─ emit Approval(owner: 0x0000000000000000000000000000000009999991, spender: TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], value: 0)
    │   │   │   │   ├─ [6028] KYCRegistry::getKYCStatus(1, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   ├─ [2923] SanctionsList::isSanctioned(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, 0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   │   ├─ [923] SanctionsList::isSanctioned(0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   ├─ [923] SanctionsList::isSanctioned(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000009999991, to: TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], value: 1000000000000000000 [1e18])
    │   │   │   │   └─ ← [Return] true
    │   │   │   └─ ← [Return] true
    │   │   ├─ [2438] DeltaCheckHarness::getPriceData() [staticcall]
    │   │   │   └─ ← [Return] 100000000000000000000 [1e20], 1712081123 [1.712e9]
    │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000009999991, value: 100000000000000000000 [1e20])
    │   │   ├─ emit TransferShares(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000009999991, sharesValue: 10000000000000000000000 [1e22])
    │   │   └─ ← [Stop] 
    │   └─ ← [Return] 
    ├─ [0] VM::stopPrank()
    │   └─ ← [Return] 
    ├─ [3156] DeltaCheckHarness::setPrice(1)
    │   └─ ← [Stop] 
    ├─ [2666] TokenProxy::balanceOf(0x0000000000000000000000000000000009999991) [staticcall]
    │   ├─ [1868] ROUSG::balanceOf(0x0000000000000000000000000000000009999991) [delegatecall]
    │   │   ├─ [438] DeltaCheckHarness::getPriceData() [staticcall]
    │   │   │   └─ ← [Return] 1, 1712081123 [1.712e9]
    │   │   └─ ← [Return] 1
    │   └─ ← [Return] 1
    ├─ [1413] TokenProxy::balanceOf(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   ├─ [615] CashKYCSenderReceiver::balanceOf(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [delegatecall]
    │   │   └─ ← [Return] 1000000000000000000 [1e18]
    │   └─ ← [Return] 1000000000000000000 [1e18]
    ├─ [0] VM::prank(0x0000000000000000000000000000000009999991)
    │   └─ ← [Return] 
    ├─ [43386] TokenProxy::unwrap(1)
    │   ├─ [42591] ROUSG::unwrap(1) [delegatecall]
    │   │   ├─ [438] DeltaCheckHarness::getPriceData() [staticcall]
    │   │   │   └─ ← [Return] 1, 1712081123 [1.712e9]
    │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, 0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   ├─ [923] SanctionsList::isSanctioned(0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   └─ ← [Return] false
    │   │   │   └─ ← [Return] true
    │   │   ├─ [32487] TokenProxy::transfer(0x0000000000000000000000000000000009999991, 1000000000000000000 [1e18])
    │   │   │   ├─ [31686] CashKYCSenderReceiver::transfer(0x0000000000000000000000000000000009999991, 1000000000000000000 [1e18]) [delegatecall]
    │   │   │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   ├─ [923] SanctionsList::isSanctioned(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   ├─ [923] SanctionsList::isSanctioned(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, 0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   │   ├─ [923] SanctionsList::isSanctioned(0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ emit Transfer(from: TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], to: 0x0000000000000000000000000000000009999991, value: 1000000000000000000 [1e18])
    │   │   │   │   └─ ← [Return] true
    │   │   │   └─ ← [Return] true
    │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000009999991, to: 0x0000000000000000000000000000000000000000, value: 1)
    │   │   ├─ emit TransferShares(from: 0x0000000000000000000000000000000009999991, to: 0x0000000000000000000000000000000000000000, sharesValue: 10000000000000000000000 [1e22])
    │   │   └─ ← [Stop] 
    │   └─ ← [Return] 
    ├─ [2666] TokenProxy::balanceOf(0x0000000000000000000000000000000009999991) [staticcall]
    │   ├─ [1868] ROUSG::balanceOf(0x0000000000000000000000000000000009999991) [delegatecall]
    │   │   ├─ [438] DeltaCheckHarness::getPriceData() [staticcall]
    │   │   │   └─ ← [Return] 1, 1712081123 [1.712e9]
    │   │   └─ ← [Return] 0
    │   └─ ← [Return] 0
    ├─ [1413] TokenProxy::balanceOf(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   ├─ [615] CashKYCSenderReceiver::balanceOf(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [delegatecall]
    │   │   └─ ← [Return] 0
    │   └─ ← [Return] 0
    ├─ [1413] TokenProxy::balanceOf(0x0000000000000000000000000000000009999991) [staticcall]
    │   ├─ [615] CashKYCSenderReceiver::balanceOf(0x0000000000000000000000000000000009999991) [delegatecall]
    │   │   └─ ← [Return] 1000000000000000000 [1e18]
    │   └─ ← [Return] 1000000000000000000 [1e18]
    └─ ← [Stop] 

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 26.22s (3.07s CPU time)

Ran 1 test suite in 86.92s (26.22s CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Detailed test results - testFail_unvalidated_pricedata testFail successful (maximum positive int256 value i.e. $2**255-1)

[⠒] Compiling...
[⠢] Compiling 168 files with 0.8.16
[⠰] Solc 0.8.16 finished in 10.51s
Compiler run successful with warnings:
<snip warnings>

Ran 1 test for forge-tests/ousg/rOUSG.t.sol:Test_rOUSG_ETH
[PASS] testFail_unvalidated_pricedata() (gas: 229777)
Logs:
  ROUSG deployed 0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A
  OUSG Instant Manager deployed 0xa0Cb889707d426A7A386870A03bc70d1b0697598

Traces:
  [189977] Test_rOUSG_ETH::testFail_unvalidated_pricedata()
    ├─ [0] VM::prank(0xAEd4caF2E535D964165B4392342F71bac77e8367)
    │   └─ ← [Return] 
    ├─ [64185] TokenProxy::mint(0x0000000000000000000000000000000009999991, 1000000000000000000 [1e18])
    │   ├─ [56887] CashKYCSenderReceiver::mint(0x0000000000000000000000000000000009999991, 1000000000000000000 [1e18]) [delegatecall]
    │   │   ├─ [8528] KYCRegistry::getKYCStatus(1, 0xAEd4caF2E535D964165B4392342F71bac77e8367) [staticcall]
    │   │   │   ├─ [2923] SanctionsList::isSanctioned(0xAEd4caF2E535D964165B4392342F71bac77e8367) [staticcall]
    │   │   │   │   └─ ← [Return] false
    │   │   │   └─ ← [Return] true
    │   │   ├─ [6028] KYCRegistry::getKYCStatus(1, 0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   ├─ [2923] SanctionsList::isSanctioned(0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   └─ ← [Return] false
    │   │   │   └─ ← [Return] true
    │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000009999991, value: 1000000000000000000 [1e18])
    │   │   └─ ← [Stop] 
    │   └─ ← [Return] 
    ├─ [0] VM::startPrank(0x0000000000000000000000000000000009999991)
    │   └─ ← [Return] 
    ├─ [25492] TokenProxy::approve(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], 1000000000000000000 [1e18])
    │   ├─ [24691] CashKYCSenderReceiver::approve(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], 1000000000000000000 [1e18]) [delegatecall]
    │   │   ├─ emit Approval(owner: 0x0000000000000000000000000000000009999991, spender: TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], value: 1000000000000000000 [1e18])
    │   │   └─ ← [Return] true
    │   └─ ← [Return] true
    ├─ [116957] TokenProxy::wrap(1000000000000000000 [1e18])
    │   ├─ [109662] ROUSG::wrap(1000000000000000000 [1e18]) [delegatecall]
    │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, 0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   ├─ [923] SanctionsList::isSanctioned(0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   └─ ← [Return] false
    │   │   │   └─ ← [Return] true
    │   │   ├─ [41225] TokenProxy::transferFrom(0x0000000000000000000000000000000009999991, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], 1000000000000000000 [1e18])
    │   │   │   ├─ [40418] CashKYCSenderReceiver::transferFrom(0x0000000000000000000000000000000009999991, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], 1000000000000000000 [1e18]) [delegatecall]
    │   │   │   │   ├─ emit Approval(owner: 0x0000000000000000000000000000000009999991, spender: TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], value: 0)
    │   │   │   │   ├─ [6028] KYCRegistry::getKYCStatus(1, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   ├─ [2923] SanctionsList::isSanctioned(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, 0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   │   ├─ [923] SanctionsList::isSanctioned(0x0000000000000000000000000000000009999991) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ [2028] KYCRegistry::getKYCStatus(1, TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   ├─ [923] SanctionsList::isSanctioned(TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A]) [staticcall]
    │   │   │   │   │   │   └─ ← [Return] false
    │   │   │   │   │   └─ ← [Return] true
    │   │   │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000009999991, to: TokenProxy: [0x7ff9C67c93D9f7318219faacB5c619a773AFeF6A], value: 1000000000000000000 [1e18])
    │   │   │   │   └─ ← [Return] true
    │   │   │   └─ ← [Return] true
    │   │   ├─ [2438] DeltaCheckHarness::getPriceData() [staticcall]
    │   │   │   └─ ← [Return] 100000000000000000000 [1e20], 1712077271 [1.712e9]
    │   │   ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000009999991, value: 100000000000000000000 [1e20])
    │   │   ├─ emit TransferShares(from: 0x0000000000000000000000000000000000000000, to: 0x0000000000000000000000000000000009999991, sharesValue: 10000000000000000000000 [1e22])
    │   │   └─ ← [Stop] 
    │   └─ ← [Return] 
    ├─ [0] VM::stopPrank()
    │   └─ ← [Return] 
    ├─ [3156] DeltaCheckHarness::setPrice(57896044618658097711785492504343953926634992332820282019728792003956564819967 [5.789e76])
    │   └─ ← [Stop] 
    ├─ [2562] TokenProxy::balanceOf(0x0000000000000000000000000000000009999991) [staticcall]
    │   ├─ [1760] ROUSG::balanceOf(0x0000000000000000000000000000000009999991) [delegatecall]
    │   │   ├─ [438] DeltaCheckHarness::getPriceData() [staticcall]
    │   │   │   └─ ← [Return] 57896044618658097711785492504343953926634992332820282019728792003956564819967 [5.789e76], 1712077271 [1.712e9]
    │   │   └─ ← [Revert] panic: arithmetic underflow or overflow (0x11)
    │   └─ ← [Revert] panic: arithmetic underflow or overflow (0x11)
    └─ ← [Revert] panic: arithmetic underflow or overflow (0x11)

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 26.68s (2.90s CPU time)

Ran 1 test suite in 52.67s (26.68s CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Tools Used

Foundry

Recommended Mitigation Steps

Implement safeguards such as data validation, fallback mechanism, deviation checks and timestamp checks for ROUSG::getOUSGPrice (and IRWAOracle::getPriceData) to ensure a robust price oracle integration.

Assessed type

Invalid Validation

c4-pre-sort commented 6 months ago

0xRobocop marked the issue as primary issue

0xRobocop commented 6 months ago

Using this report to dupe other reports about oracle sanity checks.

The setPrice function in RWAOracleExternalComparisonCheck.sol is controlled by Ondo and is restricted by a Chainlink oracle with sanity checks.

c4-pre-sort commented 6 months ago

0xRobocop marked the issue as sufficient quality report

c4-pre-sort commented 6 months ago

0xRobocop marked the issue as insufficient quality report

3docSec commented 6 months ago

Invalid, see contest readme for "Publicly known issues":

We are aware that the SHV price could differ from the OUSG portfolio, so any findings related to this price discrepancy is out of scope.

c4-judge commented 6 months ago

3docSec marked the issue as unsatisfactory: Out of scope

c4-judge commented 6 months ago

3docSec marked the issue as unsatisfactory: Out of scope