TW
Tripwire
Find contracts. Test them. Review real vulns.

Analysis Run

019c0ea9-0919-70a6-b4c7-3e776897cc66

failed
Chain ID
1
Address
Block Number
Created
Fri, Jan 30, 2026 11:28 AM
Review Summary

What survived the funnel

Open this run to answer one question: is this real attacker-relevant behavior with real impact, or just normal contract plumbing?

Confirmed
0
Validated
0
Source
Verified
Review Backing
Present
Best current signal
Untrusted DELEGATECALL target reachable
crit 0 high 0 proxy context implementation known
Review Checklist
1. Read the findings table first. Ignore raw jobs until the result looks real.
2. Confirm attacker control, not just the existence of a sink.
3. Confirm money or privilege impact.
4. Keep it if the behavior is real. Kill it if this is normal proxy, admin, or upgrade plumbing.

Processing Jobs

Status & attempts
ID Type Status Attempts Heartbeat
41991 artifact.fetch complete 1 / 3 2 months ago
41992 proxy.resolve complete 1 / 3 2 months ago
41993 tool.cast_disasm complete 1 / 3 2 months ago
41994 analysis.bundle complete 1 / 3 2 months ago
41995 capability.graph complete 1 / 3 2 months ago
41996 detector.run complete 1 / 3 2 months ago
41997 validation.fork complete 1 / 3 2 months ago
42397 report.consolidate complete 1 / 6 2 months ago
42398 tool.slither failed 2 / 2 2 months ago

Artifact

Runtime bytecode: available
Creation TX:
Deployer:
Proxy: yes confirmed
Verified Source: yes
Proxy evidence
{
    "method": "etherscan+onchain",
    "status": "confirmed",
    "etherscan_hint": {
        "source": "etherscan",
        "etherscan": {
            "proxy_flag": true,
            "implementation": "0xf59c19eb032ff3301b6695b58303470a79098771"
        }
    },
    "implementation": "0xf59c19eb032ff3301b6695b58303470a79098771",
    "onchain_method": "eip1967"
}

Slither

tool.slither
Status
failed slither failed (exit 1): 'forge clean' running (wd: /tmp/slither-1tjk16al) 'forge config --json' running 'forge build --build-info --skip ./test/** ./script/** --force' running (wd: /tmp/slither-1tjk16al) Traceback (most recent call last): File "/var/www/tripwire/.venv/bin/slither", line 10, in <module> sys.exit(main()) ~~~~^^ File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 776, in main main_impl(all_detector_classes=detectors, all_printer_classes=printers) ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 882, in main_impl ) = process_all(filename, args, detector_classes, printer_classes) ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 96, in process_all compilations = compile_all(target, **vars(args)) File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 722, in compile_all compilations.append(CryticCompile(target, **kwargs)) ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^ File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 211, in __init__ self._compile(**kwargs) ~~~~~~~~~~~~~^^^^^^^^^^ File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 633, in _compile self._platform.compile(self, **kwargs) ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^ File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/platform/foundry.py", line 102, in compile hardhat_like_parsing( ~~~~~~~~~~~~~~~~~~~~^ crytic_compile, str(self._target), build_directory, str(self._project_root) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/platform/hardhat.py", line 52, in hardhat_like_parsing raise InvalidCompilation(txt) crytic_compile.platform.exceptions.InvalidCompilation: Compilation failed. Can you run build command? /tmp/slither-1tjk16al/out/build-info is not a directory.
Attempts
2 / 2
Findings
0
Solc
View stderr
Traceback (most recent call last):
  File "/var/www/tripwire/worker/worker.py", line 198, in main
    payload = dispatch_job(job_type, job_id, job_meta, run_data, config, laravel_client)
  File "/var/www/tripwire/worker/worker.py", line 114, in dispatch_job
    return slither_run.run(job_id, job_meta, run_data, config, log, laravel_client)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/var/www/tripwire/worker/jobs/slither_run.py", line 1084, in run
    stdout_text, stderr_text, result_json = _run_slither(
                                            ~~~~~~~~~~~~^
        workspace,
        ^^^^^^^^^^
    ...<4 lines>...
        target_path=target_path,
        ^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/var/www/tripwire/worker/jobs/slither_run.py", line 958, in _run_slither
    raise RuntimeError(f"slither failed (exit {result.returncode}): {stderr_text or stdout_text}")
RuntimeError: slither failed (exit 1): 'forge clean' running (wd: /tmp/slither-1tjk16al)
'forge config --json' running
'forge build --build-info --skip ./test/** ./script/** --force' running (wd: /tmp/slither-1tjk16al)
Traceback (most recent call last):
  File "/var/www/tripwire/.venv/bin/slither", line 10, in <module>
    sys.exit(main())
             ~~~~^^
  File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 776, in main
    main_impl(all_detector_classes=detectors, all_printer_classes=printers)
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 882, in main_impl
    ) = process_all(filename, args, detector_classes, printer_classes)
        ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 96, in process_all
    compilations = compile_all(target, **vars(args))
  File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 722, in compile_all
    compilations.append(CryticCompile(target, **kwargs))
                        ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
  File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 211, in __init__
    self._compile(**kwargs)
    ~~~~~~~~~~~~~^^^^^^^^^^
  File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 633, in _compile
    self._platform.compile(self, **kwargs)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/platform/foundry.py", line 102, in compile
    hardhat_like_parsing(
    ~~~~~~~~~~~~~~~~~~~~^
        crytic_compile, str(self._target), build_directory, str(self._project_root)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/platform/hardhat.py", line 52, in hardhat_like_parsing
    raise InvalidCompilation(txt)
crytic_compile.platform.exceptions.InvalidCompilation: Compilation failed. Can you run build command?
/tmp/slither-1tjk16al/out/build-info is not a directory.

Codex

report.consolidate
Job Status
complete
Attempts
1 / 6
Findings
2
No findings?
no
Summary
Two issues found: oracle price is trusted without freshness/validity checks, and redeem cancellations return shares to the receiver instead of the original owner.
View stdout
{"no_findings":false,"summary":"Two issues found: oracle price is trusted without freshness/validity checks, and redeem cancellations return shares to the receiver instead of the original owner.","findings":[{"severity":"high","category":"oracle","title":"Oracle price used without freshness/validity checks enables share mispricing","exploit_scenario":"If the oracle can be manipulated or becomes stale, an attacker can mint shares at an artificially low price and later redeem at a higher price to drain assets, or lock in inflated redemption amounts via requestRedeem. Because conversions and totalAssets are driven solely by getLatestPrice and only require price > 0, mispriced oracle data directly affects deposits and redemptions.","recommendation":"Add oracle validity checks in the vault (timestamp freshness, max deviation from anchor/TWAP), or enforce pausability on stale/abnormal updates. Consider integrating oracle safeguards locally instead of relying on implicit oracle correctness.","evidence":"totalAssets, _convertToShares, and _convertToAssets all use IYoOracle.getLatestPrice(address(this)) and only require price > 0, with no timestamp or deviation checks.","locations":["src/YoVault_V2.sol:239","src/YoVault_V2.sol:283","src/YoVault_V2.sol:291"]},{"severity":"low","category":"other","title":"Canceled redeems return shares to receiver, not the original owner","exploit_scenario":"A user can request redeem to a third-party receiver. If the operator later cancels, the shares are transferred to the receiver (not the owner), potentially locking or gifting shares away from the original owner. The comment says “transfer the shares back to the owner,” but the implementation uses receiver, which can lead to unintended loss if receiver != owner.","recommendation":"Record the original owner in PendingRedeem and return shares to that owner on cancel, or enforce receiver == owner when requesting redeem if cancellations should restore ownership.","evidence":"cancelRedeem reduces pending and then transfers shares to receiver instead of the original owner; no owner is tracked in PendingRedeem.","locations":["src/YoVault_V2.sol:196","src/YoVault_V2.sol:210"]}]}
View stderr
OpenAI Codex v0.77.0 (research preview)
--------
workdir: /tmp/codex-7ey0vym0
model: gpt-5.2-codex
provider: openai
approval: never
sandbox: read-only
reasoning effort: high
reasoning summaries: auto
session id: 019c0f5b-3701-7123-aef1-d252ab14a05c
--------
user
Context: The user requested the proxy at 0x3a43aec53490cb9fa922847385d82fe25d0e9de7.
Audit the implementation at 0xf59c19eb032ff3301b6695b58303470a79098771.
Findings should refer to the implementation unless explicitly about proxy mechanics.

You are a security auditor. Audit this Solidity codebase for exploitable vulnerabilities.
Focus on: reentrancy, access control, upgradeability/proxy issues, signature validation, oracle manipulation,
accounting/invariant breaks, external call patterns, unchecked return values, and dangerous delegatecall.

Scope rules:
- You MUST fully read `AUDIT_BUNDLE.txt` before concluding. It contains the complete contents of all first-party Solidity sources in this workspace.
- Treat `lib/` and `@openzeppelin/` as third-party dependencies; skip them unless there is a concrete misuse angle in first-party code.
- If there are only dependency files and no first-party sources, set no_findings=true and explain in summary.

Output MUST be valid JSON matching the provided schema.
- If you find nothing meaningful: set no_findings=true and findings=[].
- Otherwise: set no_findings=false and include findings with severity/category/title and file/line locations when possible.

Output constraints (IMPORTANT):
- severity MUST be exactly one of: info, low, medium, high, critical (lowercase).
- category MUST be exactly one of: access_control, reentrancy, math, oracle, upgradeability, auth, other.
Keep summary short and concrete.
mcp startup: no servers
exec
/bin/bash -lc ls in /tmp/codex-7ey0vym0 succeeded in 7ms:
AUDIT_BUNDLE.txt
codex-output-schema.json
node_modules
src
exec
/bin/bash -lc 'cat AUDIT_BUNDLE.txt' in /tmp/codex-7ey0vym0 succeeded in 7ms:
This file concatenates the full contents of first-party Solidity sources for auditing.
Do not treat dependency code under lib/ or @openzeppelin/ as first-party.

================================================================================
FILE: src/YoVault_V2.sol
================================================================================
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {Errors} from "./libraries/Errors.sol";
import {IYoVault} from "./interfaces/IYoVault.sol";
import {IYoOracle} from "./interfaces/IYoOracle.sol";

import {Compatible} from "./base/Compatible.sol";
import {AuthUpgradeable, Authority} from "./base/AuthUpgradeable.sol";

import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
exec
/bin/bash -lc "nl -ba src/YoVault_V2.sol | sed -n '90,260p'" in /tmp/codex-7ey0vym0 succeeded in 8ms:
    90	
    91	    // ========================================= PUBLIC FUNCTIONS =========================================
    92	
    93	    /// @notice Allows the vault operator to manage the vault.
    94	    /// @param target The target contract to make a call to.
    95	    /// @param data The data to send to the target contract.
    96	    /// @param value The amount of native assets to send with the call.
    97	    function manage(
    98	        address target,
    99	        bytes calldata data,
   100	        uint256 value
   101	    ) external requiresAuth returns (bytes memory result) {
   102	        bytes4 functionSig = bytes4(data);
   103	        require(
   104	            authority().canCall(msg.sender, target, functionSig),
   105	            Errors.TargetMethodNotAuthorized(target, functionSig)
   106	        );
   107	
   108	        result = target.functionCallWithValue(data, value);
   109	    }
exec
/bin/bash -lc "nl -ba src/YoVault_V2.sol | sed -n '300,420p'" in /tmp/codex-7ey0vym0 succeeded in 6ms:
   300	    function getImplementation() external view returns (address) {
   301	        AddressSlot storage r;
   302	        assembly ("memory-safe") {
   303	            r.slot := _IMPLEMENTATION_SLOT
   304	        }
   305	        return r.value;
   306	    }
   307	
   308	    /// @dev Preview taking an entry fee on deposit. See {IERC4626-previewDeposit}.
   309	    function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
   310	        uint256 fee = _feeOnTotal(assets, feeOnDeposit);
   311	        return super.previewDeposit(assets - fee);
   312	    }
   313	
   314	    /// @dev Preview adding an entry fee on mint. See {IERC4626-previewMint}.
   315	    function previewMint(uint256 shares) public view virtual override returns (uint256) {
   316	        uint256 assets = super.previewMint(shares);
   317	        return assets + _feeOnRaw(assets, feeOnDeposit);
   318	    }
   319	
exec
/bin/bash -lc "nl -ba src/YoVault_V2.sol | sed -n '250,320p'" in /tmp/codex-7ey0vym0 succeeded in 6ms:
   250	    /// @notice Get the amount of assets and shares that are pending redemption.
   251	    /// @param user The address of the user.
   252	    function pendingRedeemRequest(address user) public view returns (uint256 assets, uint256 pendingShares) {
   253	        return (_pendingRedeem[user].assets, _pendingRedeem[user].shares);
   254	    }
   255	
   256	    //============================== OVERRIDES ===============================
   257	
   258	    /// @dev Override the default `deposit` function to add the `whenNotPaused` modifier.
   259	    function deposit(uint256 assets, address receiver) public override whenNotPaused returns (uint256) {
   260	        return super.deposit(assets, receiver);
   261	    }
   262	
   263	    /// @dev Override the default `mint` function to add the `whenNotPaused` modifier.
   264	    function mint(uint256 shares, address receiver) public override whenNotPaused returns (uint256) {
   265	        return super.mint(shares, receiver);
   266	    }
   267	
   268	    /// @notice This method is disabled. Use `requestRedeem` or `redeem`instead.
   269	    function withdraw(uint256, address, address) public override whenNotPaused returns (uint256) {
codex
{"no_findings":false,"summary":"Two issues found: oracle price is trusted without freshness/validity checks, and redeem cancellations return shares to the receiver instead of the original owner.","findings":[{"severity":"high","category":"oracle","title":"Oracle price used without freshness/validity checks enables share mispricing","exploit_scenario":"If the oracle can be manipulated or becomes stale, an attacker can mint shares at an artificially low price and later redeem at a higher price to drain assets, or lock in inflated redemption amounts via requestRedeem. Because conversions and totalAssets are driven solely by getLatestPrice and only require price > 0, mispriced oracle data directly affects deposits and redemptions.","recommendation":"Add oracle validity checks in the vault (timestamp freshness, max deviation from anchor/TWAP), or enforce pausability on stale/abnormal updates. Consider integrating oracle safeguards locally instead of relying on implicit oracle correctness.","evidence":"totalAssets, _convertToShares, and _convertToAssets all use IYoOracle.getLatestPrice(address(this)) and only require price > 0, with no timestamp or deviation checks.","locations":["src/YoVault_V2.sol:239","src/YoVault_V2.sol:283","src/YoVault_V2.sol:291"]},{"severity":"low","category":"other","title":"Canceled redeems return shares to receiver, not the original owner","exploit_scenario":"A user can request redeem to a third-party receiver. If the operator later cancels, the shares are transferred to the receiver (not the owner), potentially locking or gifting shares away from the original owner. The comment says “transfer the shares back to the owner,” but the implementation uses receiver, which can lead to unintended loss if receiver != owner.","recommendation":"Record the original owner in PendingRedeem and return shares to that owner on cancel, or enforce receiver == owner when requesting redeem if cancellations should restore ownership.","evidence":"cancelRedeem reduces pending and then transfers shares to receiver instead of the original owner; no owner is tracked in PendingRedeem.","locations":["src/YoVault_V2.sol:196","src/YoVault_V2.sol:210"]}]}
tokens used
26,728
Metadata
{
    "codex": {
        "ran_at": "2026-01-30T14:46:46.018479+00:00",
        "returncode": 0
    },
    "project": {
        "mode": "source",
        "file_count": 28,
        "import_count": 37,
        "first_party_contracts_count": 6
    },
    "summary": "Two issues found: oracle price is trusted without freshness/validity checks, and redeem cancellations return shares to the receiver instead of the original owner.",
    "raw_final": {
        "summary": "Two issues found: oracle price is trusted without freshness/validity checks, and redeem cancellations return shares to the receiver instead of the original owner.",
        "findings": [
            {
                "title": "Oracle price used without freshness/validity checks enables share mispricing",
                "category": "oracle",
                "evidence": "totalAssets, _convertToShares, and _convertToAssets all use IYoOracle.getLatestPrice(address(this)) and only require price > 0, with no timestamp or deviation checks.",
                "severity": "high",
                "locations": [
                    "src/YoVault_V2.sol:239",
                    "src/YoVault_V2.sol:283",
                    "src/YoVault_V2.sol:291"
                ],
                "recommendation": "Add oracle validity checks in the vault (timestamp freshness, max deviation from anchor/TWAP), or enforce pausability on stale/abnormal updates. Consider integrating oracle safeguards locally instead of relying on implicit oracle correctness.",
                "exploit_scenario": "If the oracle can be manipulated or becomes stale, an attacker can mint shares at an artificially low price and later redeem at a higher price to drain assets, or lock in inflated redemption amounts via requestRedeem. Because conversions and totalAssets are driven solely by getLatestPrice and only require price > 0, mispriced oracle data directly affects deposits and redemptions."
            },
            {
                "title": "Canceled redeems return shares to receiver, not the original owner",
                "category": "other",
                "evidence": "cancelRedeem reduces pending and then transfers shares to receiver instead of the original owner; no owner is tracked in PendingRedeem.",
                "severity": "low",
                "locations": [
                    "src/YoVault_V2.sol:196",
                    "src/YoVault_V2.sol:210"
                ],
                "recommendation": "Record the original owner in PendingRedeem and return shares to that owner on cancel, or enforce receiver == owner when requesting redeem if cancellations should restore ownership.",
                "exploit_scenario": "A user can request redeem to a third-party receiver. If the operator later cancels, the shares are transferred to the receiver (not the owner), potentially locking or gifting shares away from the original owner. The comment says \u201ctransfer the shares back to the owner,\u201d but the implementation uses receiver, which can lead to unintended loss if receiver != owner."
            }
        ],
        "no_findings": false
    },
    "no_findings": false,
    "proxy_context": {
        "proxy_run_id": "019c0ea9-0919-70a6-b4c7-3e776897cc66",
        "proxy_address": "0x3a43aec53490cb9fa922847385d82fe25d0e9de7",
        "implementation_run_id": "019c0eab-5d2a-7148-a859-77ddcfaad2fb",
        "implementation_address": "0xf59c19eb032ff3301b6695b58303470a79098771"
    },
    "schema_version": 1
}

Opcode Heuristics

tool.cast_disasm
Delegatecall
2
Selfdestruct
0
CREATE2
0
CALL-family (heavy)
0
EXT*/BALANCE
2
Total opcodes
681
Flags
delegatecall_present
View cast disassembly output
00000000: PUSH1 0x80
00000002: PUSH1 0x40
00000004: MSTORE
00000005: PUSH2 0x000c
00000008: PUSH2 0x000e
0000000b: JUMP
0000000c: JUMPDEST
0000000d: STOP
0000000e: JUMPDEST
0000000f: PUSH32 0x000000000000000000000000d460cf1f5d764acad1c3276c549ee5f1bb671473
00000030: PUSH1 0x01
00000032: PUSH1 0x01
00000034: PUSH1 0xa0
00000036: SHL
00000037: SUB
00000038: AND
00000039: CALLER
0000003a: SUB
0000003b: PUSH2 0x00c4
0000003e: JUMPI
0000003f: PUSH0
00000040: CALLDATALOAD
00000041: PUSH32 0xffffffff00000000000000000000000000000000000000000000000000000000
00000062: AND
00000063: PUSH32 0x4f1ef28600000000000000000000000000000000000000000000000000000000
00000084: EQ
00000085: PUSH2 0x00ba
00000088: JUMPI
00000089: PUSH1 0x40
0000008b: MLOAD
0000008c: PUSH32 0xd2b576ec00000000000000000000000000000000000000000000000000000000
000000ad: DUP2
000000ae: MSTORE
000000af: PUSH1 0x04
000000b1: ADD
000000b2: PUSH1 0x40
000000b4: MLOAD
000000b5: DUP1
000000b6: SWAP2
000000b7: SUB
000000b8: SWAP1
000000b9: REVERT
000000ba: JUMPDEST
000000bb: PUSH2 0x00c2
000000be: PUSH2 0x00cc
000000c1: JUMP
000000c2: JUMPDEST
000000c3: JUMP
000000c4: JUMPDEST
000000c5: PUSH2 0x00c2
000000c8: PUSH2 0x00fa
000000cb: JUMP
000000cc: JUMPDEST
000000cd: PUSH0
000000ce: DUP1
000000cf: PUSH2 0x00db
000000d2: CALLDATASIZE
000000d3: PUSH1 0x04
000000d5: DUP2
000000d6: DUP5
000000d7: PUSH2 0x03c9
000000da: JUMP
000000db: JUMPDEST
000000dc: DUP2
000000dd: ADD
000000de: SWAP1
000000df: PUSH2 0x00e8
000000e2: SWAP2
000000e3: SWAP1
000000e4: PUSH2 0x041d
000000e7: JUMP
000000e8: JUMPDEST
000000e9: SWAP2
000000ea: POP
000000eb: SWAP2
000000ec: POP
000000ed: PUSH2 0x00f6
000000f0: DUP3
000000f1: DUP3
000000f2: PUSH2 0x010a
000000f5: JUMP
000000f6: JUMPDEST
000000f7: POP
000000f8: POP
000000f9: JUMP
000000fa: JUMPDEST
000000fb: PUSH2 0x00c2
000000fe: PUSH2 0x0105
00000101: PUSH2 0x0164
00000104: JUMP
00000105: JUMPDEST
00000106: PUSH2 0x019b
00000109: JUMP
0000010a: JUMPDEST
0000010b: PUSH2 0x0113
0000010e: DUP3
0000010f: PUSH2 0x01b9
00000112: JUMP
00000113: JUMPDEST
00000114: PUSH1 0x40
00000116: MLOAD
00000117: PUSH1 0x01
00000119: PUSH1 0x01
0000011b: PUSH1 0xa0
0000011d: SHL
0000011e: SUB
0000011f: DUP4
00000120: AND
00000121: SWAP1
00000122: PUSH32 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b
00000143: SWAP1
00000144: PUSH0
00000145: SWAP1
00000146: LOG2
00000147: DUP1
00000148: MLOAD
00000149: ISZERO
0000014a: PUSH2 0x015c
0000014d: JUMPI
0000014e: PUSH2 0x0157
00000151: DUP3
00000152: DUP3
00000153: PUSH2 0x0265
00000156: JUMP
00000157: JUMPDEST
00000158: POP
00000159: POP
0000015a: POP
0000015b: JUMP
0000015c: JUMPDEST
0000015d: PUSH2 0x00f6
00000160: PUSH2 0x02d7
00000163: JUMP
00000164: JUMPDEST
00000165: PUSH0
00000166: PUSH2 0x0196
00000169: PUSH32 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
0000018a: SLOAD
0000018b: PUSH1 0x01
0000018d: PUSH1 0x01
0000018f: PUSH1 0xa0
00000191: SHL
00000192: SUB
00000193: AND
00000194: SWAP1
00000195: JUMP
00000196: JUMPDEST
00000197: SWAP1
00000198: POP
00000199: SWAP1
0000019a: JUMP
0000019b: JUMPDEST
0000019c: CALLDATASIZE
0000019d: PUSH0
0000019e: PUSH0
0000019f: CALLDATACOPY
000001a0: PUSH0
000001a1: PUSH0
000001a2: CALLDATASIZE
000001a3: PUSH0
000001a4: DUP5
000001a5: GAS
000001a6: DELEGATECALL
000001a7: RETURNDATASIZE
000001a8: PUSH0
000001a9: PUSH0
000001aa: RETURNDATACOPY
000001ab: DUP1
000001ac: DUP1
000001ad: ISZERO
000001ae: PUSH2 0x01b5
000001b1: JUMPI
000001b2: RETURNDATASIZE
000001b3: PUSH0
000001b4: RETURN
000001b5: JUMPDEST
000001b6: RETURNDATASIZE
000001b7: PUSH0
000001b8: REVERT
000001b9: JUMPDEST
000001ba: DUP1
000001bb: PUSH1 0x01
000001bd: PUSH1 0x01
000001bf: PUSH1 0xa0
000001c1: SHL
000001c2: SUB
000001c3: AND
000001c4: EXTCODESIZE
000001c5: PUSH0
000001c6: SUB
000001c7: PUSH2 0x020c
000001ca: JUMPI
000001cb: PUSH1 0x40
000001cd: MLOAD
000001ce: PUSH32 0x4c9c8ce300000000000000000000000000000000000000000000000000000000
000001ef: DUP2
000001f0: MSTORE
000001f1: PUSH1 0x01
000001f3: PUSH1 0x01
000001f5: PUSH1 0xa0
000001f7: SHL
000001f8: SUB
000001f9: DUP3
000001fa: AND
000001fb: PUSH1 0x04
000001fd: DUP3
000001fe: ADD
000001ff: MSTORE
00000200: PUSH1 0x24
00000202: ADD
00000203: JUMPDEST
00000204: PUSH1 0x40
00000206: MLOAD
00000207: DUP1
00000208: SWAP2
00000209: SUB
0000020a: SWAP1
0000020b: REVERT
0000020c: JUMPDEST
0000020d: PUSH32 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
0000022e: DUP1
0000022f: SLOAD
00000230: PUSH32 0xffffffffffffffffffffffff0000000000000000000000000000000000000000
00000251: AND
00000252: PUSH1 0x01
00000254: PUSH1 0x01
00000256: PUSH1 0xa0
00000258: SHL
00000259: SUB
0000025a: SWAP3
0000025b: SWAP1
0000025c: SWAP3
0000025d: AND
0000025e: SWAP2
0000025f: SWAP1
00000260: SWAP2
00000261: OR
00000262: SWAP1
00000263: SSTORE
00000264: JUMP
00000265: JUMPDEST
00000266: PUSH1 0x60
00000268: PUSH0
00000269: PUSH0
0000026a: DUP5
0000026b: PUSH1 0x01
0000026d: PUSH1 0x01
0000026f: PUSH1 0xa0
00000271: SHL
00000272: SUB
00000273: AND
00000274: DUP5
00000275: PUSH1 0x40
00000277: MLOAD
00000278: PUSH2 0x0281
0000027b: SWAP2
0000027c: SWAP1
0000027d: PUSH2 0x04ee
00000280: JUMP
00000281: JUMPDEST
00000282: PUSH0
00000283: PUSH1 0x40
00000285: MLOAD
00000286: DUP1
00000287: DUP4
00000288: SUB
00000289: DUP2
0000028a: DUP6
0000028b: GAS
0000028c: DELEGATECALL
0000028d: SWAP2
0000028e: POP
0000028f: POP
00000290: RETURNDATASIZE
00000291: DUP1
00000292: PUSH0
00000293: DUP2
00000294: EQ
00000295: PUSH2 0x02b9
00000298: JUMPI
00000299: PUSH1 0x40
0000029b: MLOAD
0000029c: SWAP2
0000029d: POP
0000029e: PUSH1 0x1f
000002a0: NOT
000002a1: PUSH1 0x3f
000002a3: RETURNDATASIZE
000002a4: ADD
000002a5: AND
000002a6: DUP3
000002a7: ADD
000002a8: PUSH1 0x40
000002aa: MSTORE
000002ab: RETURNDATASIZE
000002ac: DUP3
000002ad: MSTORE
000002ae: RETURNDATASIZE
000002af: PUSH0
000002b0: PUSH1 0x20
000002b2: DUP5
000002b3: ADD
000002b4: RETURNDATACOPY
000002b5: PUSH2 0x02be
000002b8: JUMP
000002b9: JUMPDEST
000002ba: PUSH1 0x60
000002bc: SWAP2
000002bd: POP
000002be: JUMPDEST
000002bf: POP
000002c0: SWAP2
000002c1: POP
000002c2: SWAP2
000002c3: POP
000002c4: PUSH2 0x02ce
000002c7: DUP6
000002c8: DUP4
000002c9: DUP4
000002ca: PUSH2 0x030f
000002cd: JUMP
000002ce: JUMPDEST
000002cf: SWAP6
000002d0: SWAP5
000002d1: POP
000002d2: POP
000002d3: POP
000002d4: POP
000002d5: POP
000002d6: JUMP
000002d7: JUMPDEST
000002d8: CALLVALUE
000002d9: ISZERO
000002da: PUSH2 0x00c2
000002dd: JUMPI
000002de: PUSH1 0x40
000002e0: MLOAD
000002e1: PUSH32 0xb398979f00000000000000000000000000000000000000000000000000000000
00000302: DUP2
00000303: MSTORE
00000304: PUSH1 0x04
00000306: ADD
00000307: PUSH1 0x40
00000309: MLOAD
0000030a: DUP1
0000030b: SWAP2
0000030c: SUB
0000030d: SWAP1
0000030e: REVERT
0000030f: JUMPDEST
00000310: PUSH1 0x60
00000312: DUP3
00000313: PUSH2 0x0324
00000316: JUMPI
00000317: PUSH2 0x031f
0000031a: DUP3
0000031b: PUSH2 0x0387
0000031e: JUMP
0000031f: JUMPDEST
00000320: PUSH2 0x0380
00000323: JUMP
00000324: JUMPDEST
00000325: DUP2
00000326: MLOAD
00000327: ISZERO
00000328: DUP1
00000329: ISZERO
0000032a: PUSH2 0x033b
0000032d: JUMPI
0000032e: POP
0000032f: PUSH1 0x01
00000331: PUSH1 0x01
00000333: PUSH1 0xa0
00000335: SHL
00000336: SUB
00000337: DUP5
00000338: AND
00000339: EXTCODESIZE
0000033a: ISZERO
0000033b: JUMPDEST
0000033c: ISZERO
0000033d: PUSH2 0x037d
00000340: JUMPI
00000341: PUSH1 0x40
00000343: MLOAD
00000344: PUSH32 0x9996b31500000000000000000000000000000000000000000000000000000000
00000365: DUP2
00000366: MSTORE
00000367: PUSH1 0x01
00000369: PUSH1 0x01
0000036b: PUSH1 0xa0
0000036d: SHL
0000036e: SUB
0000036f: DUP6
00000370: AND
00000371: PUSH1 0x04
00000373: DUP3
00000374: ADD
00000375: MSTORE
00000376: PUSH1 0x24
00000378: ADD
00000379: PUSH2 0x0203
0000037c: JUMP
0000037d: JUMPDEST
0000037e: POP
0000037f: DUP1
00000380: JUMPDEST
00000381: SWAP4
00000382: SWAP3
00000383: POP
00000384: POP
00000385: POP
00000386: JUMP
00000387: JUMPDEST
00000388: DUP1
00000389: MLOAD
0000038a: ISZERO
0000038b: PUSH2 0x0397
0000038e: JUMPI
0000038f: DUP1
00000390: MLOAD
00000391: DUP1
00000392: DUP3
00000393: PUSH1 0x20
00000395: ADD
00000396: REVERT
00000397: JUMPDEST
00000398: PUSH1 0x40
0000039a: MLOAD
0000039b: PUSH32 0xd6bda27500000000000000000000000000000000000000000000000000000000
000003bc: DUP2
000003bd: MSTORE
000003be: PUSH1 0x04
000003c0: ADD
000003c1: PUSH1 0x40
000003c3: MLOAD
000003c4: DUP1
000003c5: SWAP2
000003c6: SUB
000003c7: SWAP1
000003c8: REVERT
000003c9: JUMPDEST
000003ca: PUSH0
000003cb: PUSH0
000003cc: DUP6
000003cd: DUP6
000003ce: GT
000003cf: ISZERO
000003d0: PUSH2 0x03d7
000003d3: JUMPI
000003d4: PUSH0
000003d5: PUSH0
000003d6: REVERT
000003d7: JUMPDEST
000003d8: DUP4
000003d9: DUP7
000003da: GT
000003db: ISZERO
000003dc: PUSH2 0x03e3
000003df: JUMPI
000003e0: PUSH0
000003e1: PUSH0
000003e2: REVERT
000003e3: JUMPDEST
000003e4: POP
000003e5: POP
000003e6: DUP3
000003e7: ADD
000003e8: SWAP4
000003e9: SWAP2
000003ea: SWAP1
000003eb: SWAP3
000003ec: SUB
000003ed: SWAP2
000003ee: POP
000003ef: JUMP
000003f0: JUMPDEST
000003f1: PUSH32 0x4e487b7100000000000000000000000000000000000000000000000000000000
00000412: PUSH0
00000413: MSTORE
00000414: PUSH1 0x41
00000416: PUSH1 0x04
00000418: MSTORE
00000419: PUSH1 0x24
0000041b: PUSH0
0000041c: REVERT
0000041d: JUMPDEST
0000041e: PUSH0
0000041f: PUSH0
00000420: PUSH1 0x40
00000422: DUP4
00000423: DUP6
00000424: SUB
00000425: SLT
00000426: ISZERO
00000427: PUSH2 0x042e
0000042a: JUMPI
0000042b: PUSH0
0000042c: PUSH0
0000042d: REVERT
0000042e: JUMPDEST
0000042f: DUP3
00000430: CALLDATALOAD
00000431: PUSH1 0x01
00000433: PUSH1 0x01
00000435: PUSH1 0xa0
00000437: SHL
00000438: SUB
00000439: DUP2
0000043a: AND
0000043b: DUP2
0000043c: EQ
0000043d: PUSH2 0x0444
00000440: JUMPI
00000441: PUSH0
00000442: PUSH0
00000443: REVERT
00000444: JUMPDEST
00000445: SWAP2
00000446: POP
00000447: PUSH1 0x20
00000449: DUP4
0000044a: ADD
0000044b: CALLDATALOAD
0000044c: PUSH8 0xffffffffffffffff
00000455: DUP2
00000456: GT
00000457: ISZERO
00000458: PUSH2 0x045f
0000045b: JUMPI
0000045c: PUSH0
0000045d: PUSH0
0000045e: REVERT
0000045f: JUMPDEST
00000460: DUP4
00000461: ADD
00000462: PUSH1 0x1f
00000464: DUP2
00000465: ADD
00000466: DUP6
00000467: SGT
00000468: PUSH2 0x046f
0000046b: JUMPI
0000046c: PUSH0
0000046d: PUSH0
0000046e: REVERT
0000046f: JUMPDEST
00000470: DUP1
00000471: CALLDATALOAD
00000472: PUSH8 0xffffffffffffffff
0000047b: DUP2
0000047c: GT
0000047d: ISZERO
0000047e: PUSH2 0x0489
00000481: JUMPI
00000482: PUSH2 0x0489
00000485: PUSH2 0x03f0
00000488: JUMP
00000489: JUMPDEST
0000048a: PUSH1 0x40
0000048c: MLOAD
0000048d: PUSH1 0x1f
0000048f: DUP3
00000490: ADD
00000491: PUSH1 0x1f
00000493: NOT
00000494: SWAP1
00000495: DUP2
00000496: AND
00000497: PUSH1 0x3f
00000499: ADD
0000049a: AND
0000049b: DUP2
0000049c: ADD
0000049d: PUSH8 0xffffffffffffffff
000004a6: DUP2
000004a7: GT
000004a8: DUP3
000004a9: DUP3
000004aa: LT
000004ab: OR
000004ac: ISZERO
000004ad: PUSH2 0x04b8
000004b0: JUMPI
000004b1: PUSH2 0x04b8
000004b4: PUSH2 0x03f0
000004b7: JUMP
000004b8: JUMPDEST
000004b9: PUSH1 0x40
000004bb: MSTORE
000004bc: DUP2
000004bd: DUP2
000004be: MSTORE
000004bf: DUP3
000004c0: DUP3
000004c1: ADD
000004c2: PUSH1 0x20
000004c4: ADD
000004c5: DUP8
000004c6: LT
000004c7: ISZERO
000004c8: PUSH2 0x04cf
000004cb: JUMPI
000004cc: PUSH0
000004cd: PUSH0
000004ce: REVERT
000004cf: JUMPDEST
000004d0: DUP2
000004d1: PUSH1 0x20
000004d3: DUP5
000004d4: ADD
000004d5: PUSH1 0x20
000004d7: DUP4
000004d8: ADD
000004d9: CALLDATACOPY
000004da: PUSH0
000004db: PUSH1 0x20
000004dd: DUP4
000004de: DUP4
000004df: ADD
000004e0: ADD
000004e1: MSTORE
000004e2: DUP1
000004e3: SWAP4
000004e4: POP
000004e5: POP
000004e6: POP
000004e7: POP
000004e8: SWAP3
000004e9: POP
000004ea: SWAP3
000004eb: SWAP1
000004ec: POP
000004ed: JUMP
000004ee: JUMPDEST
000004ef: PUSH0
000004f0: DUP3
000004f1: MLOAD
000004f2: PUSH0
000004f3: JUMPDEST
000004f4: DUP2
000004f5: DUP2
000004f6: LT
000004f7: ISZERO
000004f8: PUSH2 0x050d
000004fb: JUMPI
000004fc: PUSH1 0x20
000004fe: DUP2
000004ff: DUP7
00000500: ADD
00000501: DUP2
00000502: ADD
00000503: MLOAD
00000504: DUP6
00000505: DUP4
00000506: ADD
00000507: MSTORE
00000508: ADD
00000509: PUSH2 0x04f3
0000050c: JUMP
0000050d: JUMPDEST
0000050e: POP
0000050f: PUSH0
00000510: SWAP3
00000511: ADD
00000512: SWAP2
00000513: DUP3
00000514: MSTORE
00000515: POP
00000516: SWAP2
00000517: SWAP1
00000518: POP
00000519: JUMP
0000051a: INVALID
0000051b: LOG1
0000051c: PUSH5 0x736f6c6343
00000522: STOP
00000523: ADDMOD
00000524: SHR
00000525: STOP
00000526: EXP

Findings

validated = confirmed for call sinks; sink observed for others
Severity Category Tool Title Confidence Validated Confirmed Details
critical upgradeability detector Untrusted DELEGATECALL target reachable 70 no no
view
trace_id: 0x93f8a5c28e0c905a946bcd39f7118ef25c114ca28cae672e2edb0239898b48f2
call_targets: 0xf59c19eb032ff3301b6695b58303470a79098771
target_varies: no
classification: constant_target
validation_json
{
    "sink": "DELEGATECALL",
    "errors": 0,
    "status": "sink_reached",
    "attempts": 1,
    "trace_id": "0x93f8a5c28e0c905a946bcd39f7118ef25c114ca28cae672e2edb0239898b48f2",
    "confirmed": false,
    "trace_mode": "callTracer",
    "call_targets": [
        "0xf59c19eb032ff3301b6695b58303470a79098771"
    ],
    "matched_probe": null,
    "target_varies": false,
    "classification": "constant_target"
}
witness_json
{
    "notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
    "constraints": [],
    "entrypoints": [
        {
            "calldata": "0x",
            "selector": "fallback",
            "calldata_variants": [
                "0x"
            ]
        }
    ]
}
evidence_json
{
    "examples": [
        {
            "pc": 422,
            "opcode": "DELEGATECALL",
            "returndata_checked": null,
            "value_expression_category": "n/a",
            "target_expression_category": "computed"
        },
        {
            "pc": 652,
            "opcode": "DELEGATECALL",
            "returndata_checked": null,
            "value_expression_category": "n/a",
            "target_expression_category": "computed"
        }
    ],
    "guards_detected": [],
    "delegatecall_count": 2,
    "untrusted_delegatecall_count": 2
}
high oracle codex Oracle price used without freshness/validity checks enables share mispricing 85 no
view
evidence_json
{
    "evidence": "totalAssets, _convertToShares, and _convertToAssets all use IYoOracle.getLatestPrice(address(this)) and only require price > 0, with no timestamp or deviation checks.",
    "locations": [
        "src/YoVault_V2.sol:239",
        "src/YoVault_V2.sol:283",
        "src/YoVault_V2.sol:291"
    ],
    "recommendation": "Add oracle validity checks in the vault (timestamp freshness, max deviation from anchor/TWAP), or enforce pausability on stale/abnormal updates. Consider integrating oracle safeguards locally instead of relying on implicit oracle correctness.",
    "exploit_scenario": "If the oracle can be manipulated or becomes stale, an attacker can mint shares at an artificially low price and later redeem at a higher price to drain assets, or lock in inflated redemption amounts via requestRedeem. Because conversions and totalAssets are driven solely by getLatestPrice and only require price > 0, mispriced oracle data directly affects deposits and redemptions."
}
medium upgradeability cast DELEGATECALL present 80 no
view
evidence_json
{
    "notes": "delegatecall enables execution in caller context; common in proxies/upgradeable patterns",
    "delegatecall_count": 2
}
low other codex Canceled redeems return shares to receiver, not the original owner 65 no
view
evidence_json
{
    "evidence": "cancelRedeem reduces pending and then transfers shares to receiver instead of the original owner; no owner is tracked in PendingRedeem.",
    "locations": [
        "src/YoVault_V2.sol:196",
        "src/YoVault_V2.sol:210"
    ],
    "recommendation": "Record the original owner in PendingRedeem and return shares to that owner on cancel, or enforce receiver == owner when requesting redeem if cancellations should restore ownership.",
    "exploit_scenario": "A user can request redeem to a third-party receiver. If the operator later cancels, the shares are transferred to the receiver (not the owner), potentially locking or gifting shares away from the original owner. The comment says \u201ctransfer the shares back to the owner,\u201d but the implementation uses receiver, which can lead to unintended loss if receiver != owner."
}