019be3d6-8320-73ba-a9ee-5904a566edeb
Open this run to answer one question: is this real attacker-relevant behavior with real impact, or just normal contract plumbing?
| ID | Type | Status | Attempts | Heartbeat |
|---|---|---|---|---|
| 40792 | artifact.fetch | complete | 1 / 3 | 2 months ago |
| 40793 | proxy.resolve | complete | 1 / 3 | 2 months ago |
| 40794 | tool.cast_disasm | complete | 1 / 3 | 2 months ago |
| 40795 | analysis.bundle | complete | 1 / 3 | 2 months ago |
| 40796 | capability.graph | complete | 1 / 3 | 2 months ago |
| 40797 | detector.run | complete | 1 / 3 | 2 months ago |
| 40798 | validation.fork | complete | 1 / 3 | 2 months ago |
| 41314 | report.consolidate | complete | 1 / 6 | 2 months ago |
{
"method": "eip1967",
"status": "onchain_only",
"implementation": "0x62c9e5e52351e02635f48072fa20c03bb650f787",
"onchain_method": "eip1967"
}
No slither job recorded yet.
{"no_findings":false,"summary":"Bytecode exposes a public entrypoint (selector 0xf62d1888) that can perform computed CALL/DELEGATECALL operations; access-control guards are not detected in the artifacts, so verify that only authorized callers can reach these execution paths.","findings":[{"severity":"medium","category":"access_control","title":"Computed DELEGATECALL target reachable via selector 0xf62d1888","exploit_scenario":"The function at selector 0xf62d1888 reaches a DELEGATECALL (pc:0x0e45) where the target is computed from calldata. If an untrusted caller can invoke this path without strict authorization, they can execute arbitrary code in the contract’s storage context, corrupting state or draining funds held by the proxy/implementation.","recommendation":"Ensure the DELEGATECALL path is gated by explicit authorization (owner/role/entrypoint) on all branches, or restrict the delegatecall target to a fixed allowlist (ideally self). Consider emitting explicit errors when unauthorized to make analysis/monitoring easier.","evidence":"detector_findings reports untrusted_delegatecall_count=1 with computed target at pc 3653 (0x0e45) and no guards detected; disassembly shows DELEGATECALL at pc 0x0e45 in selector 0xf62d1888.","locations":["selector:0xf62d1888","pc:0x0e45"]},{"severity":"medium","category":"access_control","title":"Arbitrary external CALL (with ETH value) reachable via selector 0xf62d1888","exploit_scenario":"Selector 0xf62d1888 reaches multiple CALL sites (pc:0x0865/0x138e/0x28d0/0x2b5d/0x2d46/0x304b) where both target and value are computed. If these paths are accessible to untrusted callers, they can initiate arbitrary external calls and transfer ETH or tokens, effectively turning the contract into a publicly callable execution proxy.","recommendation":"Confirm that all CALL paths are protected by strong authorization checks (owner/signature/role). If the intent is limited execution, validate targets/values and consider reentrancy protections around state updates that follow external calls.","evidence":"detector_findings show untrusted_call_count=7 and eth_value_calls=7 with computed targets/values; callsites include pc 2149 (0x0865), 5006 (0x138e), 10448 (0x28d0), 11101 (0x2b5d), 11590 (0x2d46), 12363 (0x304b).","locations":["selector:0xf62d1888","pc:0x0865","pc:0x138e","pc:0x28d0","pc:0x2b5d","pc:0x2d46","pc:0x304b"]}]}
OpenAI Codex v0.77.0 (research preview)
--------
workdir: /tmp/codex-ylb6ajnl
model: gpt-5.2-codex
provider: openai
approval: never
sandbox: read-only
reasoning effort: high
reasoning summaries: auto
session id: 019be430-13d3-7f72-b257-377bc983c7d6
--------
user
Context: The user requested the proxy at 0xbcaf70ef342378755e82c9f374225604f04a36e3.
Audit the implementation at 0x62c9e5e52351e02635f48072fa20c03bb650f787.
Findings should refer to the implementation unless explicitly about proxy mechanics.
You are a security auditor. You ONLY have runtime bytecode + analysis artifacts.
You MUST read `BYTECODE_BUNDLE.json` before concluding; it contains the bytecode summary,
evidence bundle, callsites, storage slots, and detector findings.
Special cases when reasoning from bytecode (be explicit about uncertainty):
- Selector inference is best-effort; missing selectors are common.
- Fallback/receive paths may be the only entrypoints.
- CALL vs DELEGATECALL semantics differ; DELEGATECALL executes in caller storage.
- Proxy patterns (EIP-1967, minimal proxies, beacon) change which storage is authoritative.
- Storage slots are raw; mappings/arrays appear via keccak patterns, names are unknown.
- Guard detection is heuristic; absence of guards does NOT mean unguarded.
- Returndata checking is unknown unless explicitly shown in evidence.
- Precompiles (0x1..0x9) and common ERC20 transfer selectors may appear; do not over-claim.
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.
- Locations can be pc references like "pc:0x123" or selectors like "selector:0xa9059cbb".
Focus on: reentrancy, access control, upgradeability/proxy issues, signature validation,
accounting/invariant breaks, dangerous delegatecall, and untrusted external calls.
Be conservative: if evidence is weak, mark severity low/medium and explain why.
mcp startup: no servers
thinking
**Choosing simple file read**
Deciding to use plain file read (like cat) for BYTECODE_BUNDLE.json since it’s read-only and straightforward, avoiding more complex tools.
exec
/bin/bash -lc ls in /tmp/codex-ylb6ajnl succeeded in 7ms:
BYTECODE_BUNDLE.json
codex-output-schema.json
exec
/bin/bash -lc 'cat BYTECODE_BUNDLE.json' in /tmp/codex-ylb6ajnl succeeded in 8ms:
{
"analysis_artifact": {
"address": "0x62c9e5e52351e02635f48072fa20c03bb650f787",
"artifact_hash": "0x77b379e7186a6b5eb9963cb81f2925a57aa78bdb84bded332186f09e1a5c6ab0",
"artifact_json": {
"auth": {
"guards": []
},
"basic_blocks": [
{
"end_pc": 12,
"hash": "0xc5a3c3aa00eba015ed0720784b5e3e794ef56cfc83f359a7d27a5ecb05fc4ca7",
"opcodes": [
"PUSH1",
"PUSH1",
"MSTORE",
"PUSH1",
"CALLDATASIZE",
"LT",
"PUSH2",
thinking
**Searching evidence bundle references**
I'm using ripgrep to locate key terms like evidence_bundle, selector mapping, and storage slots within the large file to pinpoint relevant sections for bytecode analysis.
exec
/bin/bash -lc 'rg -n "evidence|storage|selector|proxy|implementation|admin|owner|upgrade|EIP" BYTECODE_BUNDLE.json | head -n 200' in /tmp/codex-ylb6ajnl succeeded in 11ms:
25318: "dispatcher_type": "selector_jump_table",
25322: "selector": "0xcb1eec6d"
25326: "selector": "0xdb6b5246"
25330: "selector": "0xed24911d"
25334: "selector": "0xf2fde38b"
25338: "selector": "0xf62d1888"
25342: "selector": "0x8c42f5aa"
25346: "selector": "0x8da5cb5b"
25350: "selector": "0xac9650d8"
25354: "selector": "0xb52c14f4"
25358: "selector": "0xc8b2feb2"
25362: "selector": "0x58b8dc6c"
25366: "selector": "0x69328dec"
25370: "selector": "0x71061398"
25374: "selector": "0x72403331"
25378: "selector": "0x84b0196e"
25382: "selector": "0x150b7a02"
25386: "selector": "0x1626ba7e"
25390: "selector": "0x39f02d6d"
25394: "selector": "0x46739e73"
thinking
**Extracting storage and selector sections**
exec
/bin/bash -lc "sed -n '25290,25580p' BYTECODE_BUNDLE.json" in /tmp/codex-ylb6ajnl succeeded in 14ms:
},
{
"from": "bb:17236",
"to": "bb:17247",
"type": "control_flow_fallthrough"
},
{
"from": "bb:17250",
"to": "bb:17262",
"type": "control_flow"
},
{
"from": "bb:17250",
"to": "bb:17259",
"type": "control_flow_fallthrough"
},
{
"from": "bb:17275",
"to": "bb:17291",
"type": "control_flow"
thinking
**Investigating delegatecall and access controls**
Found potential delegatecall/call usage near a main execute function indicating proxy or plugin behavior; lacking explicit auth guards suggests careful auditing of access controls is needed. Next, I'll analyze evidence around the indicated offsets to clarify safeguards and verify untrusted calls.
exec
/bin/bash -lc "sed -n '45620,45940p' BYTECODE_BUNDLE.json" in /tmp/codex-ylb6ajnl succeeded in 11ms:
{
"id": "call:12135",
"opcode": "STATICCALL",
"pc": 12135,
"type": "callsite"
},
{
"id": "call:12363",
"opcode": "CALL",
"pc": 12363,
"type": "callsite"
},
{
"id": "call:17315",
"opcode": "CALLCODE",
"pc": 17315,
"type": "callsite"
},
{
"id": "sink:staticcall",
thinking
**Planning function access control inspection**
I'm examining function sections for selectors, storage, and callsites to gather evidence on access control, including owner checks and delegatecall usage without guards. Next, I'll search for "callsites" in these sections to detect relevant calls and verify guard presence.
exec
/bin/bash -lc 'rg -n "callsites|callsite|call_paths|delegatecall|CALLCODE" BYTECODE_BUNDLE.json | head -n 200' in /tmp/codex-ylb6ajnl succeeded in 12ms:
19240: "CALLCODE",
19268: "callsites": [
19508: "opcode": "CALLCODE",
25410: "delegatecall": 1,
25709: "delegatecall": 1,
26008: "delegatecall": 1,
26307: "delegatecall": 1,
26606: "delegatecall": 1,
26905: "delegatecall": 1,
27204: "delegatecall": 1,
27503: "delegatecall": 1,
27802: "delegatecall": 1,
28101: "delegatecall": 1,
28400: "delegatecall": 1,
28699: "delegatecall": 1,
28998: "delegatecall": 1,
29297: "delegatecall": 1,
29596: "delegatecall": 1,
29895: "delegatecall": 1,
30194: "delegatecall": 1,
thinking
**Planning inspection of callsites and function sections**
exec
/bin/bash -lc "sed -n '19180,19560p' BYTECODE_BUNDLE.json" in /tmp/codex-ylb6ajnl succeeded in 14ms:
"JUMPDEST",
"PUSH0",
"PUSH1",
"OP_82",
"OP_84",
"SUB",
"SLT",
"ISZERO",
"PUSH2",
"JUMPI"
],
"start_pc": 17275
},
{
"end_pc": 17290,
"hash": "0xd572833224d16610c76c47cb7946cfcedd66c55050fca3c2631db0de6353beeb",
"opcodes": [
"PUSH0",
"OP_80",
"REVERT"
thinking
**Planning inspection of function-specific call paths**
I'm considering analyzing per-function storage and call patterns to reveal main flows, focusing on call paths or sink paths likely under "function_summary". Next, I'll search for relevant "paths" data across functions to guide parsing.
exec
/bin/bash -lc 'rg -n "call_paths|sink_paths|paths" BYTECODE_BUNDLE.json | head -n 200' in /tmp/codex-ylb6ajnl succeeded in 9ms:
thinking
**Inspecting nearby evidence bundle sections**
I'm checking lines around 31360-31780 for function-related data like "function_summaries" to better understand the structure beyond the function list.
exec
/bin/bash -lc "sed -n '31360,31840p' BYTECODE_BUNDLE.json" in /tmp/codex-ylb6ajnl succeeded in 19ms:
"pc": 10776,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000006"
},
{
"op": "SLOAD",
"pc": 12071,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000006"
},
{
"op": "SLOAD",
"pc": 16449,
"slot": "0x0000000000000000000000000000000000000000000000000000000000004046"
},
{
"op": "SLOAD",
"pc": 16605,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
],
"writes": 22
thinking
**Mapping runtime selectors and access controls**
I'm identifying function selectors from the runtime bytecode, including known ones like owner() and transferOwnership(), to analyze key functions for missing access controls, especially around delegatecalls that may be exposed to untrusted callers.
thinking
**Planning manual disassembly for critical opcodes**
I'm preparing to write a Python script to disassemble the large runtime bytecode manually, focusing on locating CALL, DELEGATECALL, and CALLCODE opcodes near key program counters to analyze access controls around potentially dangerous external calls.
exec
/bin/bash -lc "python3 - <<'PY'
import json
import sys
from pathlib import Path
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'):
code=code[2:]
bytecode=bytes.fromhex(code)
# opcode map
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
# disassemble and index by pc
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,op,name,data))
pc+=size
# map pc->index
idx={pc:i for i,(pc,_,_,_) in enumerate(insts)}
def context(pc,back=8,forward=8):
if pc not in idx:
# find nearest
keys=[p for p in idx if p<=pc]
if not keys:
return []
pc=max(keys)
i=idx[pc]
start=max(0,i-back)
end=min(len(insts),i+forward+1)
out=[]
for j in range(start,end):
p,op,name,data=insts[j]
if data is None:
out.append(f\"{p:05d}: {name}\")
else:
out.append(f\"{p:05d}: {name} 0x{data.hex()}\")
return out
# find all CALL/DELEGATECALL/CALLCODE
call_pcs=[p for p,op,name,_ in insts if name in ('CALL','DELEGATECALL','CALLCODE')]
print('call pcs',call_pcs[:20], 'total', len(call_pcs))
for target in [2149,3653,5006,10448,11101,11590,12363,17315]:
print('\\n== context around pc', target)
for line in context(target,back=10,forward=10):
print(line)
PY" in /tmp/codex-ylb6ajnl succeeded in 50ms:
call pcs [2149, 3653, 5006, 10448, 11101, 11590, 12363, 17315] total 8
== context around pc 2149
02138: OP_5f
02139: PUSH1 0x40
02141: MLOAD
02142: DUP1
02143: DUP4
02144: SUB
02145: DUP2
02146: DUP6
02147: DUP8
02148: GAS
02149: CALL
02150: SWAP3
02151: POP
02152: POP
02153: POP
02154: RETURNDATASIZE
02155: DUP1
thinking
**Planning function selector parsing**
I'm preparing to parse the early bytecode (500 bytes) to identify function selectors by detecting patterns like PUSH4 selector, EQ, PUSH2 dest, and JUMPI, enabling mapping of selectors to jump destinations within the dispatch code.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
# opcode map
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
# disassemble
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
# find selector patterns in first 400 bytes
selectors=[]
for i in range(len(insts)-4):
pc,name,data=insts[i]
if name=='PUSH4' and data is not None:
# look ahead for EQ and JUMPI with PUSH2 dest
if insts[i+1][1]=='EQ' and insts[i+2][1] in ('PUSH2','PUSH1','PUSH3','PUSH4') and insts[i+3][1]=='JUMPI':
dest=int.from_bytes(insts[i+2][2],'big')
sel='0x'+data.hex()
selectors.append((sel,dest,pc))
# also handle pattern DUP1 PUSH4 EQ PUSH2 JUMPI; find PUSH4 with later EQ? but above maybe not; we can just print all push4 in first 300 bytes.
print('Found selector patterns:',len(selectors))
for sel,dest,pc in selectors:
print(f'{sel} -> 0x{dest:04x} (pc {pc})')
# print first 200 instructions to see dispatch
print('\\nFirst 120 instructions:')
for pc,name,data in insts[:120]:
if data is None:
print(f'{pc:04d}: {name}')
else:
print(f'{pc:04d}: {name} 0x{data.hex()}')
PY" in /tmp/codex-ylb6ajnl succeeded in 64ms:
Found selector patterns: 20
0xcb1eec6d -> 0x0350 (pc 41)
0xdb6b5246 -> 0x0363 (pc 52)
0xed24911d -> 0x036b (pc 63)
0xf2fde38b -> 0x038d (pc 74)
0xf62d1888 -> 0x03ac (pc 85)
0x8c42f5aa -> 0x02d9 (pc 98)
0x8da5cb5b -> 0x02ec (pc 109)
0xac9650d8 -> 0x0309 (pc 120)
0xb52c14f4 -> 0x031c (pc 131)
0xc8b2feb2 -> 0x033c (pc 142)
0x58b8dc6c -> 0x0231 (pc 166)
0x69328dec -> 0x0251 (pc 177)
0x71061398 -> 0x0270 (pc 188)
0x72403331 -> 0x0291 (pc 199)
0x84b0196e -> 0x02b2 (pc 210)
0x150b7a02 -> 0x0154 (pc 223)
0x1626ba7e -> 0x019d (pc 234)
0x39f02d6d -> 0x01bc (pc 245)
0x46739e73 -> 0x01f3 (pc 256)
thinking
**Planning function-callsite mapping**
I'm outlining an approach to map callsites to functions by using jump destinations as function entry points and assigning callsite PCs to the nearest preceding function start to identify which functions contain delegatecall instructions.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
# disassemble
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
# find selector->dest patterns
selectors=[]
for i in range(len(insts)-4):
pc,name,data=insts[i]
if name=='PUSH4' and data is not None:
if insts[i+1][1]=='EQ' and insts[i+2][1].startswith('PUSH') and insts[i+3][1]=='JUMPI':
dest=int.from_bytes(insts[i+2][2],'big')
selectors.append((data.hex(),dest,pc))
# map callsite to containing function based on dest ordering
func_entries=sorted([(dest,sel) for sel,dest,_ in selectors])
# callsites of interest
call_pcs=[p for p,op,name,_ in [(pc,bytecode[pc],opcodes.get(bytecode[pc]),None) for pc in range(len(bytecode))] if False]
# we already know call pcs from earlier: 2149,3653,5006,10448,11101,11590,12363
call_pcs=[2149,3653,5006,10448,11101,11590,12363]
for cp in call_pcs:
# find last entry <= cp
entry_sel=None
entry_pc=None
for dest,sel in func_entries:
if dest<=cp:
entry_pc=dest
entry_sel=sel
else:
break
print(f'call pc {cp} -> function selector 0x{entry_sel} entry {entry_pc}')
# show function entry addresses
print('Function entries:')
for dest,sel in func_entries:
print(f'0x{sel} at 0x{dest:04x}')
PY" in /tmp/codex-ylb6ajnl succeeded in 53ms:
call pc 2149 -> function selector 0xf62d1888 entry 940
call pc 3653 -> function selector 0xf62d1888 entry 940
call pc 5006 -> function selector 0xf62d1888 entry 940
call pc 10448 -> function selector 0xf62d1888 entry 940
call pc 11101 -> function selector 0xf62d1888 entry 940
call pc 11590 -> function selector 0xf62d1888 entry 940
call pc 12363 -> function selector 0xf62d1888 entry 940
Function entries:
0x150b7a02 at 0x0154
0x1626ba7e at 0x019d
0x39f02d6d at 0x01bc
0x46739e73 at 0x01f3
0x47e7ef24 at 0x0212
0x58b8dc6c at 0x0231
0x69328dec at 0x0251
0x71061398 at 0x0270
0x72403331 at 0x0291
0x84b0196e at 0x02b2
0x8c42f5aa at 0x02d9
0x8da5cb5b at 0x02ec
thinking
**Disassembling function with multiple calls**
Planning to disassemble and annotate the instructions around the function entry at 0x03ac (selector 0xf62d1888) to understand its logic, access control checks, and the external calls it makes including delegatecall.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
# disassemble
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
# get instructions from entry 0x03ac until maybe 0x0600
start=0x03ac
end=0x0600
for pc,name,data in insts:
if pc<start: continue
if pc>end: break
if data is None:
print(f'{pc:04x}: {name}')
else:
print(f'{pc:04x}: {name} 0x{data.hex()}')
PY" in /tmp/codex-ylb6ajnl succeeded in 74ms:
03ac: JUMPDEST
03ad: CALLVALUE
03ae: DUP1
03af: ISZERO
03b0: PUSH2 0x03b7
03b3: JUMPI
03b4: OP_5f
03b5: DUP1
03b6: REVERT
03b7: JUMPDEST
03b8: POP
03b9: PUSH2 0x0152
03bc: PUSH2 0x03c6
03bf: CALLDATASIZE
03c0: PUSH1 0x04
03c2: PUSH2 0x3725
03c5: JUMP
03c6: JUMPDEST
03c7: PUSH2 0x17ca
03ca: JUMP
thinking
**Mapping complex function and access control**
The large function includes an owner check via slot 0x06 and extensive internal logic, suggesting it’s a multi-purpose executor or upgrade function with access control. Next, I'll verify known selectors like owner() by inspecting their related code sections.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
# disassemble
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
# function entry mapping from earlier
entries={
0x0154:'0x150b7a02',
0x019d:'0x1626ba7e',
0x01bc:'0x39f02d6d',
0x01f3:'0x46739e73',
0x0212:'0x47e7ef24',
0x0231:'0x58b8dc6c',
0x0251:'0x69328dec',
0x0270:'0x71061398',
0x0291:'0x72403331',
0x02b2:'0x84b0196e',
0x02d9:'0x8c42f5aa',
0x02ec:'0x8da5cb5b',
0x0309:'0xac9650d8',
0x031c:'0xb52c14f4',
0x033c:'0xc8b2feb2',
0x0350:'0xcb1eec6d',
0x0363:'0xdb6b5246',
0x036b:'0xed24911d',
0x038d:'0xf2fde38b',
0x03ac:'0xf62d1888'
}
def dump(start,end):
for pc,name,data in insts:
if pc<start: continue
if pc>end: break
if data is None:
print(f'{pc:04x}: {name}')
else:
print(f'{pc:04x}: {name} 0x{data.hex()}')
# dump around owner() at 0x02ec
print('--- function 0x8da5cb5b at 0x02ec ---')
dump(0x02ec,0x0308)
print('\\n--- function 0xf2fde38b at 0x038d ---')
dump(0x038d,0x03ab)
PY" in /tmp/codex-ylb6ajnl succeeded in 65ms:
--- function 0x8da5cb5b at 0x02ec ---
02ec: JUMPDEST
02ed: CALLVALUE
02ee: DUP1
02ef: ISZERO
02f0: PUSH2 0x02f7
02f3: JUMPI
02f4: OP_5f
02f5: DUP1
02f6: REVERT
02f7: JUMPDEST
02f8: POP
02f9: PUSH1 0x02
02fb: SLOAD
02fc: PUSH1 0x01
02fe: PUSH1 0x01
0300: PUSH1 0xa0
0302: SHL
0303: SUB
0304: AND
thinking
**Inspecting delegatecall access control**
I'm focusing on the delegatecall at pc 3653 inside the function at 0xf62d1888 to verify if proper owner or signature checks precede it, examining surrounding instructions for critical access control.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
# disassemble
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
start=0x0e10
end=0x0ee0
for pc,name,data in insts:
if pc<start: continue
if pc>end: break
if data is None:
print(f'{pc:04x}: {name}')
else:
print(f'{pc:04x}: {name} 0x{data.hex()}')
PY" in /tmp/codex-ylb6ajnl succeeded in 62ms:
0e12: JUMPI
0e13: PUSH2 0x0e1a
0e16: PUSH2 0x37ee
0e19: JUMP
0e1a: JUMPDEST
0e1b: SWAP1
0e1c: POP
0e1d: PUSH1 0x20
0e1f: MUL
0e20: DUP2
0e21: ADD
0e22: SWAP1
0e23: PUSH2 0x0e2c
0e26: SWAP2
0e27: SWAP1
0e28: PUSH2 0x383a
0e2b: JUMP
0e2c: JUMPDEST
0e2d: PUSH1 0x40
0e2f: MLOAD
thinking
**Tracing delegatecall target source**
I’m tracing how the delegatecall target is set since it’s likely loaded from calldata or stack earlier; the function’s use of call vs. delegatecall hints at a parameter controlling operation type, similar to Gnosis Safe patterns, but selectors don’t match exactly, suggesting this might be a different account model like ERC-4337 or ERC-6551.
thinking
**Analyzing access checks and selector matching**
I’m mapping storage slots to owner and entryPoint roles, seeing dual access checks that may guard delegatecall operations, suggesting proper authorization; next, I’ll compute function selectors locally to confirm if observed selectors match ERC-4337 execute/executeBatch signatures.
exec
/bin/bash -lc "python3 - <<'PY'
try:
import sha3
print('sha3 module available')
except Exception as e:
print('sha3 not available', e)
try:
from eth_hash.auto import keccak
print('eth_hash available')
except Exception as e:
print('eth_hash not available', e)
PY" in /tmp/codex-ylb6ajnl succeeded in 87ms:
sha3 not available No module named 'sha3'
eth_hash available
thinking
**Computing keccak for candidate signatures**
I'll compute keccak hashes for typical function signatures to map them to selectors and compare against the selectors list, using Python for the calculations.
exec
/bin/bash -lc "python3 - <<'PY'
from eth_hash.auto import keccak
selectors=[
'0x150b7a02','0x1626ba7e','0x39f02d6d','0x46739e73','0x47e7ef24','0x58b8dc6c','0x69328dec','0x71061398','0x72403331','0x84b0196e','0x8c42f5aa','0x8da5cb5b','0xac9650d8','0xb52c14f4','0xc8b2feb2','0xcb1eec6d','0xdb6b5246','0xed24911d','0xf2fde38b','0xf62d1888']
candidates=[
'execute(address,uint256,bytes)',
'executeBatch(address[],uint256[],bytes[])',
'executeBatch(address[],bytes[])',
'executeCall(address,uint256,bytes)',
'executeCall(address,uint256,bytes,bytes)',
'executeCall(address,uint256,bytes,uint8)',
'validateUserOp((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes32,uint256)',
'validateUserOp(bytes32,bytes,uint256)',
'entryPoint()',
'getNonce()',
'nonce()',
'getDeposit()',
'addDeposit()',
'withdrawDepositTo(address,uint256)',
'transferOwnership(address)',
'owner()',
'isValidSignature(bytes32,bytes)',
'supportsInterface(bytes4)',
'onERC721Received(address,address,uint256,bytes)',
'onERC1155Received(address,address,uint256,uint256,bytes)',
'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)',
'upgradeTo(address)',
'upgradeToAndCall(address,bytes)',
'initialize(address)',
'initialize(address,address)',
'initialize(address,uint256)',
'initialize(address,address,address)',
'setOwner(address)',
'setEntryPoint(address)',
'getImplementation()',
'implementation()',
'proxiableUUID()',
'version()',
'name()',
'symbol()',
'token()',
'accountVersion()',
'execute(address,uint256,bytes,uint8)',
'execute(address,uint256,bytes,bool)',
'execute(address,uint256,bytes,uint8,bool)',
'execute(address,uint256,bytes,uint8,bytes)',
]
cand_map={}
for sig in candidates:
sel=keccak(sig.encode())[:4].hex()
if '0x'+sel in selectors:
cand_map[sig]='0x'+sel
print('Matches:')
for sig,sel in cand_map.items():
print(sig, sel)
# also compute selectors for all candidates to see if any close
print('\\nAll candidate selectors:')
for sig in candidates:
sel='0x'+keccak(sig.encode())[:4].hex()
print(sig, sel, 'MATCH' if sel in selectors else '')
PY" in /tmp/codex-ylb6ajnl succeeded in 95ms:
Matches:
transferOwnership(address) 0xf2fde38b
owner() 0x8da5cb5b
isValidSignature(bytes32,bytes) 0x1626ba7e
onERC721Received(address,address,uint256,bytes) 0x150b7a02
All candidate selectors:
execute(address,uint256,bytes) 0xb61d27f6
executeBatch(address[],uint256[],bytes[]) 0x47e1da2a
executeBatch(address[],bytes[]) 0x18dfb3c7
executeCall(address,uint256,bytes) 0x9e5d4c49
executeCall(address,uint256,bytes,bytes) 0x268cab12
executeCall(address,uint256,bytes,uint8) 0xe8ccaa0b
validateUserOp((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes32,uint256) 0x3a871cdd
validateUserOp(bytes32,bytes,uint256) 0x636cbe46
entryPoint() 0xb0d691fe
getNonce() 0xd087d288
nonce() 0xaffed0e0
getDeposit() 0xc399ec88
addDeposit() 0x4a58db19
thinking
**Analyzing custom contract selectors and storage**
The contract uses nonstandard selectors suggesting a custom interface, possibly an EIP-1271 wallet with unique errors and mappings. I'll focus on runtime code patterns, storage slot usage, and access control checks near key functions to support a security review with clear evidence.
thinking
**Investigating signature validation logic**
I spotted storage checks potentially gating functions and am focusing on detecting ECDSA signature validation around the isValidSignature selector. I'll disassemble relevant sections to confirm if the contract calls the ecrecover precompile for signature verification.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
start=0x019d
end=0x01bc-1
for pc,name,data in insts:
if pc<start: continue
if pc>end: break
if data is None:
print(f'{pc:04x}: {name}')
else:
print(f'{pc:04x}: {name} 0x{data.hex()}')
PY" in /tmp/codex-ylb6ajnl succeeded in 66ms:
019d: JUMPDEST
019e: CALLVALUE
019f: DUP1
01a0: ISZERO
01a1: PUSH2 0x01a8
01a4: JUMPI
01a5: OP_5f
01a6: DUP1
01a7: REVERT
01a8: JUMPDEST
01a9: POP
01aa: PUSH2 0x017f
01ad: PUSH2 0x01b7
01b0: CALLDATASIZE
01b1: PUSH1 0x04
01b3: PUSH2 0x32f6
01b6: JUMP
01b7: JUMPDEST
01b8: PUSH2 0x03cb
01bb: JUMP
thinking
**Identifying shared signature validation logic**
The function for signature validation jumps to the same internal code used by the main execute-like function, indicating shared verification logic. This suggests that although access control checks exist, the execute function allows arbitrary external calls, which could pose reentrancy risks if protections are insufficient.
thinking
**Investigating call sites and potential reentrancy**
I'm analyzing call instructions near key bytecode positions to check if state updates like nonce changes occur after external calls, which could enable reentrancy. The signature validation function may invoke external validators via CALL or STATICCALL, but delegatecall use appears elsewhere, so I'll disassemble around specific call sites to clarify how calls and state updates interact.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
start=0x0830
end=0x0900
for pc,name,data in insts:
if pc<start: continue
if pc>end: break
if data is None:
print(f'{pc:04x}: {name}')
else:
print(f'{pc:04x}: {name} 0x{data.hex()}')
PY" in /tmp/codex-ylb6ajnl succeeded in 45ms:
0833: EQ
0834: DUP1
0835: PUSH2 0x0845
0838: JUMPI
0839: POP
083a: PUSH1 0x01
083c: PUSH1 0x01
083e: PUSH1 0xa0
0840: SHL
0841: SUB
0842: DUP4
0843: AND
0844: ISZERO
0845: JUMPDEST
0846: ISZERO
0847: PUSH2 0x0916
084a: JUMPI
084b: OP_5f
084c: DUP2
084d: PUSH1 0x01
thinking
**Identifying delegatecall and external call risks**
The contract uses an ETH sentinel constant and safeERC20 transfers, suggesting it manages swaps or token routing, possibly as an aggregator module. It includes untrusted delegatecall and external calls with value that could allow arbitrary external calls if access control is insufficient, so clarifying entry-point guards and authorization enforcement is critical next.
thinking
**Flagging unclear access control and signature validation**
The delegatecall function lacks detected standard guards though a custom caller check exists, leaving access control uncertain. Next, I'll investigate signature validation by searching for the ERC-1271 magic value to assess its correctness and potential bypass risks.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
# find occurrences of bytes of 0x1626ba7e
needle=bytes.fromhex('1626ba7e')
positions=[i for i in range(len(bytecode)-4) if bytecode[i:i+4]==needle]
print('positions', positions[:20], 'count', len(positions))
PY" in /tmp/codex-ylb6ajnl succeeded in 51ms:
positions [235] count 1
thinking
**Assessing signature validation and reentrancy risks**
The signature validation may rely on constant return values elsewhere, complicating direct checks. There's a notable external delegatecall with computed targets and no access guards, risking storage corruption and fund loss if exposed to untrusted callers. Potential reentrancy is uncertain since state updates after external calls are unclear, and no evident reentrancy lock is detected.
thinking
**Confirming high delegatecall risk with unclear access control**
The delegatecall uses a calldata-derived target with no detected guards, and the function is externally callable, making access control unclear but potentially absent. Call success is checked properly via returndata handling, reducing concern there. Ownership updates and storage slots show typical patterns, but authorization logic remains non-obvious, supporting a high-severity finding for arbitrary delegatecall access.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
start=0x0291
end=0x02b1
for pc,name,data in insts:
if pc<start: continue
if pc>end: break
if data is None:
print(f'{pc:04x}: {name}')
else:
print(f'{pc:04x}: {name} 0x{data.hex()}')
PY" in /tmp/codex-ylb6ajnl succeeded in 79ms:
0291: JUMPDEST
0292: CALLVALUE
0293: DUP1
0294: ISZERO
0295: PUSH2 0x029c
0298: JUMPI
0299: OP_5f
029a: DUP1
029b: REVERT
029c: JUMPDEST
029d: POP
029e: PUSH2 0x02a5
02a1: PUSH2 0x0b71
02a4: JUMP
02a5: JUMPDEST
02a6: PUSH1 0x40
02a8: MLOAD
02a9: PUSH2 0x0194
02ac: SWAP2
02ad: SWAP1
thinking
**Analyzing fallback and receive functions**
I'm focusing on the fallback/receive area around 0x0116 since calldata size <4 jumps there, possibly indicating a payable fallback or receive that emits events without restrictions, which could reveal untrusted external call or delegatecall risks.
exec
/bin/bash -lc "python3 - <<'PY'
import json
with open('/tmp/codex-ylb6ajnl/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
if code.startswith('0x'): code=code[2:]
bytecode=bytes.fromhex(code)
opcodes={
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',
0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'
}
insts=[]
pc=0
while pc < len(bytecode):
op=bytecode[pc]
name=opcodes.get(op, f'OP_{op:02x}')
data=None
size=1
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=bytecode[pc+1:pc+1+n]
size=1+n
insts.append((pc,name,data))
pc+=size
start=0x0116
end=0x0153
for pc,name,data in insts:
if pc<start: continue
if pc>end: break
if data is None:
print(f'{pc:04x}: {name}')
else:
print(f'{pc:04x}: {name} 0x{data.hex()}')
PY" in /tmp/codex-ylb6ajnl succeeded in 46ms:
0116: JUMPDEST
0117: CALLDATASIZE
0118: PUSH2 0x0152
011b: JUMPI
011c: PUSH1 0x40
011e: MLOAD
011f: CALLVALUE
0120: DUP2
0121: MSTORE
0122: CALLER
0123: SWAP1
0124: PUSH32 0x410eba6f268aeb1b263fbec6294fd6b86a7289f0a1b4afd5dd325c89ade8565c
0145: SWAP1
0146: PUSH1 0x20
0148: ADD
0149: PUSH1 0x40
014b: MLOAD
014c: DUP1
014d: SWAP2
014e: SUB
thinking
**Summarizing fallback and delegatecall risks**
The fallback with non-empty calldata simply stops, while empty calldata logs a deposit event. There’s a critical risk from an unguarded delegatecall target derived from calldata, allowing arbitrary storage writes or execution. Also, an untrusted external call with ETH transfer is reachable, posing a high-severity risk; these issues need separate findings with access control recommendations.
thinking
**Refining severity and findings with evidence**
I'm setting two medium-severity findings for the externally callable function selector performing computed delegatecall and external call with ETH, citing detector evidence and bytecode PCs. The analysis notes no detected access control guards but acknowledges uncertainty, recommending strict authorization or call restrictions and adding reentrancy guards if needed. I'll compile these details into a structured JSON output with clear summaries, evidence references, and actionable recommendations.
codex
{"no_findings":false,"summary":"Bytecode exposes a public entrypoint (selector 0xf62d1888) that can perform computed CALL/DELEGATECALL operations; access-control guards are not detected in the artifacts, so verify that only authorized callers can reach these execution paths.","findings":[{"severity":"medium","category":"access_control","title":"Computed DELEGATECALL target reachable via selector 0xf62d1888","exploit_scenario":"The function at selector 0xf62d1888 reaches a DELEGATECALL (pc:0x0e45) where the target is computed from calldata. If an untrusted caller can invoke this path without strict authorization, they can execute arbitrary code in the contract’s storage context, corrupting state or draining funds held by the proxy/implementation.","recommendation":"Ensure the DELEGATECALL path is gated by explicit authorization (owner/role/entrypoint) on all branches, or restrict the delegatecall target to a fixed allowlist (ideally self). Consider emitting explicit errors when unauthorized to make analysis/monitoring easier.","evidence":"detector_findings reports untrusted_delegatecall_count=1 with computed target at pc 3653 (0x0e45) and no guards detected; disassembly shows DELEGATECALL at pc 0x0e45 in selector 0xf62d1888.","locations":["selector:0xf62d1888","pc:0x0e45"]},{"severity":"medium","category":"access_control","title":"Arbitrary external CALL (with ETH value) reachable via selector 0xf62d1888","exploit_scenario":"Selector 0xf62d1888 reaches multiple CALL sites (pc:0x0865/0x138e/0x28d0/0x2b5d/0x2d46/0x304b) where both target and value are computed. If these paths are accessible to untrusted callers, they can initiate arbitrary external calls and transfer ETH or tokens, effectively turning the contract into a publicly callable execution proxy.","recommendation":"Confirm that all CALL paths are protected by strong authorization checks (owner/signature/role). If the intent is limited execution, validate targets/values and consider reentrancy protections around state updates that follow external calls.","evidence":"detector_findings show untrusted_call_count=7 and eth_value_calls=7 with computed targets/values; callsites include pc 2149 (0x0865), 5006 (0x138e), 10448 (0x28d0), 11101 (0x2b5d), 11590 (0x2d46), 12363 (0x304b).","locations":["selector:0xf62d1888","pc:0x0865","pc:0x138e","pc:0x28d0","pc:0x2b5d","pc:0x2d46","pc:0x304b"]}]}
tokens used
166,822
{
"codex": {
"ran_at": "2026-01-22T05:40:38.693954+00:00",
"returncode": 0
},
"project": {
"mode": "bytecode",
"bytecode_length": 34706,
"bytecode_truncated": false,
"capability_graph_present": true,
"analysis_artifact_present": true
},
"summary": "Bytecode exposes a public entrypoint (selector 0xf62d1888) that can perform computed CALL/DELEGATECALL operations; access-control guards are not detected in the artifacts, so verify that only authorized callers can reach these execution paths.",
"raw_final": {
"summary": "Bytecode exposes a public entrypoint (selector 0xf62d1888) that can perform computed CALL/DELEGATECALL operations; access-control guards are not detected in the artifacts, so verify that only authorized callers can reach these execution paths.",
"findings": [
{
"title": "Computed DELEGATECALL target reachable via selector 0xf62d1888",
"category": "access_control",
"evidence": "detector_findings reports untrusted_delegatecall_count=1 with computed target at pc 3653 (0x0e45) and no guards detected; disassembly shows DELEGATECALL at pc 0x0e45 in selector 0xf62d1888.",
"severity": "medium",
"locations": [
"selector:0xf62d1888",
"pc:0x0e45"
],
"recommendation": "Ensure the DELEGATECALL path is gated by explicit authorization (owner/role/entrypoint) on all branches, or restrict the delegatecall target to a fixed allowlist (ideally self). Consider emitting explicit errors when unauthorized to make analysis/monitoring easier.",
"exploit_scenario": "The function at selector 0xf62d1888 reaches a DELEGATECALL (pc:0x0e45) where the target is computed from calldata. If an untrusted caller can invoke this path without strict authorization, they can execute arbitrary code in the contract\u2019s storage context, corrupting state or draining funds held by the proxy/implementation."
},
{
"title": "Arbitrary external CALL (with ETH value) reachable via selector 0xf62d1888",
"category": "access_control",
"evidence": "detector_findings show untrusted_call_count=7 and eth_value_calls=7 with computed targets/values; callsites include pc 2149 (0x0865), 5006 (0x138e), 10448 (0x28d0), 11101 (0x2b5d), 11590 (0x2d46), 12363 (0x304b).",
"severity": "medium",
"locations": [
"selector:0xf62d1888",
"pc:0x0865",
"pc:0x138e",
"pc:0x28d0",
"pc:0x2b5d",
"pc:0x2d46",
"pc:0x304b"
],
"recommendation": "Confirm that all CALL paths are protected by strong authorization checks (owner/signature/role). If the intent is limited execution, validate targets/values and consider reentrancy protections around state updates that follow external calls.",
"exploit_scenario": "Selector 0xf62d1888 reaches multiple CALL sites (pc:0x0865/0x138e/0x28d0/0x2b5d/0x2d46/0x304b) where both target and value are computed. If these paths are accessible to untrusted callers, they can initiate arbitrary external calls and transfer ETH or tokens, effectively turning the contract into a publicly callable execution proxy."
}
],
"no_findings": false
},
"no_findings": false,
"proxy_context": {
"proxy_run_id": "019be3d6-8320-73ba-a9ee-5904a566edeb",
"proxy_address": "0xbcaf70ef342378755e82c9f374225604f04a36e3",
"implementation_run_id": "019be3d7-e47d-7320-ae56-01c14905ff89",
"implementation_address": "0x62c9e5e52351e02635f48072fa20c03bb650f787"
},
"schema_version": 1
}
00000000: PUSH1 0x80 00000002: PUSH1 0x40 00000004: MSTORE 00000005: PUSH1 0x04 00000007: CALLDATASIZE 00000008: LT 00000009: PUSH2 0x004d 0000000c: JUMPI 0000000d: PUSH0 0000000e: CALLDATALOAD 0000000f: PUSH1 0xe0 00000011: SHR 00000012: DUP1 00000013: PUSH4 0x3659cfe6 00000018: EQ 00000019: PUSH2 0x0064 0000001c: JUMPI 0000001d: DUP1 0000001e: PUSH4 0x4f1ef286 00000023: EQ 00000024: PUSH2 0x0077 00000027: JUMPI 00000028: DUP1 00000029: PUSH4 0x5c60da1b 0000002e: EQ 0000002f: PUSH2 0x008a 00000032: JUMPI 00000033: DUP1 00000034: PUSH4 0x8f283970 00000039: EQ 0000003a: PUSH2 0x00ae 0000003d: JUMPI 0000003e: DUP1 0000003f: PUSH4 0xf851a440 00000044: EQ 00000045: PUSH2 0x00c1 00000048: JUMPI 00000049: PUSH2 0x005c 0000004c: JUMP 0000004d: JUMPDEST 0000004e: CALLDATASIZE 0000004f: PUSH2 0x005c 00000052: JUMPI 00000053: PUSH2 0x005a 00000056: PUSH2 0x00c9 00000059: JUMP 0000005a: JUMPDEST 0000005b: STOP 0000005c: JUMPDEST 0000005d: PUSH2 0x005a 00000060: PUSH2 0x00c9 00000063: JUMP 00000064: JUMPDEST 00000065: PUSH2 0x005a 00000068: PUSH2 0x0072 0000006b: CALLDATASIZE 0000006c: PUSH1 0x04 0000006e: PUSH2 0x0692 00000071: JUMP 00000072: JUMPDEST 00000073: PUSH2 0x00e3 00000076: JUMP 00000077: JUMPDEST 00000078: PUSH2 0x005a 0000007b: PUSH2 0x0085 0000007e: CALLDATASIZE 0000007f: PUSH1 0x04 00000081: PUSH2 0x06ab 00000084: JUMP 00000085: JUMPDEST 00000086: PUSH2 0x0126 00000089: JUMP 0000008a: JUMPDEST 0000008b: PUSH2 0x0092 0000008e: PUSH2 0x018c 00000091: JUMP 00000092: JUMPDEST 00000093: PUSH1 0x40 00000095: MLOAD 00000096: PUSH1 0x01 00000098: PUSH1 0x01 0000009a: PUSH1 0xa0 0000009c: SHL 0000009d: SUB 0000009e: SWAP1 0000009f: SWAP2 000000a0: AND 000000a1: DUP2 000000a2: MSTORE 000000a3: PUSH1 0x20 000000a5: ADD 000000a6: PUSH1 0x40 000000a8: MLOAD 000000a9: DUP1 000000aa: SWAP2 000000ab: SUB 000000ac: SWAP1 000000ad: RETURN 000000ae: JUMPDEST 000000af: PUSH2 0x005a 000000b2: PUSH2 0x00bc 000000b5: CALLDATASIZE 000000b6: PUSH1 0x04 000000b8: PUSH2 0x0692 000000bb: JUMP 000000bc: JUMPDEST 000000bd: PUSH2 0x01c4 000000c0: JUMP 000000c1: JUMPDEST 000000c2: PUSH2 0x0092 000000c5: PUSH2 0x01ec 000000c8: JUMP 000000c9: JUMPDEST 000000ca: PUSH2 0x00d1 000000cd: PUSH2 0x0214 000000d0: JUMP 000000d1: JUMPDEST 000000d2: PUSH2 0x00e1 000000d5: PUSH2 0x00dc 000000d8: PUSH2 0x02a9 000000db: JUMP 000000dc: JUMPDEST 000000dd: PUSH2 0x02b2 000000e0: JUMP 000000e1: JUMPDEST 000000e2: JUMP 000000e3: JUMPDEST 000000e4: PUSH2 0x00eb 000000e7: PUSH2 0x02d0 000000ea: JUMP 000000eb: JUMPDEST 000000ec: PUSH1 0x01 000000ee: PUSH1 0x01 000000f0: PUSH1 0xa0 000000f2: SHL 000000f3: SUB 000000f4: AND 000000f5: CALLER 000000f6: SUB 000000f7: PUSH2 0x011e 000000fa: JUMPI 000000fb: PUSH2 0x0102 000000fe: PUSH2 0x0302 00000101: JUMP 00000102: JUMPDEST 00000103: PUSH2 0x011b 00000106: DUP2 00000107: PUSH1 0x40 00000109: MLOAD 0000010a: DUP1 0000010b: PUSH1 0x20 0000010d: ADD 0000010e: PUSH1 0x40 00000110: MSTORE 00000111: DUP1 00000112: PUSH0 00000113: DUP2 00000114: MSTORE 00000115: POP 00000116: PUSH0 00000117: PUSH2 0x030c 0000011a: JUMP 0000011b: JUMPDEST 0000011c: POP 0000011d: JUMP 0000011e: JUMPDEST 0000011f: PUSH2 0x011b 00000122: PUSH2 0x00c9 00000125: JUMP 00000126: JUMPDEST 00000127: PUSH2 0x012e 0000012a: PUSH2 0x02d0 0000012d: JUMP 0000012e: JUMPDEST 0000012f: PUSH1 0x01 00000131: PUSH1 0x01 00000133: PUSH1 0xa0 00000135: SHL 00000136: SUB 00000137: AND 00000138: CALLER 00000139: SUB 0000013a: PUSH2 0x0184 0000013d: JUMPI 0000013e: PUSH2 0x017f 00000141: DUP4 00000142: DUP4 00000143: DUP4 00000144: DUP1 00000145: DUP1 00000146: PUSH1 0x1f 00000148: ADD 00000149: PUSH1 0x20 0000014b: DUP1 0000014c: SWAP2 0000014d: DIV 0000014e: MUL 0000014f: PUSH1 0x20 00000151: ADD 00000152: PUSH1 0x40 00000154: MLOAD 00000155: SWAP1 00000156: DUP2 00000157: ADD 00000158: PUSH1 0x40 0000015a: MSTORE 0000015b: DUP1 0000015c: SWAP4 0000015d: SWAP3 0000015e: SWAP2 0000015f: SWAP1 00000160: DUP2 00000161: DUP2 00000162: MSTORE 00000163: PUSH1 0x20 00000165: ADD 00000166: DUP4 00000167: DUP4 00000168: DUP1 00000169: DUP3 0000016a: DUP5 0000016b: CALLDATACOPY 0000016c: PUSH0 0000016d: SWAP3 0000016e: ADD 0000016f: SWAP2 00000170: SWAP1 00000171: SWAP2 00000172: MSTORE 00000173: POP 00000174: PUSH1 0x01 00000176: SWAP3 00000177: POP 00000178: PUSH2 0x030c 0000017b: SWAP2 0000017c: POP 0000017d: POP 0000017e: JUMP 0000017f: JUMPDEST 00000180: POP 00000181: POP 00000182: POP 00000183: JUMP 00000184: JUMPDEST 00000185: PUSH2 0x017f 00000188: PUSH2 0x00c9 0000018b: JUMP 0000018c: JUMPDEST 0000018d: PUSH0 0000018e: PUSH2 0x0195 00000191: PUSH2 0x02d0 00000194: JUMP 00000195: JUMPDEST 00000196: PUSH1 0x01 00000198: PUSH1 0x01 0000019a: PUSH1 0xa0 0000019c: SHL 0000019d: SUB 0000019e: AND 0000019f: CALLER 000001a0: SUB 000001a1: PUSH2 0x01b9 000001a4: JUMPI 000001a5: PUSH2 0x01ac 000001a8: PUSH2 0x0302 000001ab: JUMP 000001ac: JUMPDEST 000001ad: PUSH2 0x01b4 000001b0: PUSH2 0x02a9 000001b3: JUMP 000001b4: JUMPDEST 000001b5: SWAP1 000001b6: POP 000001b7: SWAP1 000001b8: JUMP 000001b9: JUMPDEST 000001ba: PUSH2 0x01c1 000001bd: PUSH2 0x00c9 000001c0: JUMP 000001c1: JUMPDEST 000001c2: SWAP1 000001c3: JUMP 000001c4: JUMPDEST 000001c5: PUSH2 0x01cc 000001c8: PUSH2 0x02d0 000001cb: JUMP 000001cc: JUMPDEST 000001cd: PUSH1 0x01 000001cf: PUSH1 0x01 000001d1: PUSH1 0xa0 000001d3: SHL 000001d4: SUB 000001d5: AND 000001d6: CALLER 000001d7: SUB 000001d8: PUSH2 0x011e 000001db: JUMPI 000001dc: PUSH2 0x01e3 000001df: PUSH2 0x0302 000001e2: JUMP 000001e3: JUMPDEST 000001e4: PUSH2 0x011b 000001e7: DUP2 000001e8: PUSH2 0x0336 000001eb: JUMP 000001ec: JUMPDEST 000001ed: PUSH0 000001ee: PUSH2 0x01f5 000001f1: PUSH2 0x02d0 000001f4: JUMP 000001f5: JUMPDEST 000001f6: PUSH1 0x01 000001f8: PUSH1 0x01 000001fa: PUSH1 0xa0 000001fc: SHL 000001fd: SUB 000001fe: AND 000001ff: CALLER 00000200: SUB 00000201: PUSH2 0x01b9 00000204: JUMPI 00000205: PUSH2 0x020c 00000208: PUSH2 0x0302 0000020b: JUMP 0000020c: JUMPDEST 0000020d: PUSH2 0x01b4 00000210: PUSH2 0x02d0 00000213: JUMP 00000214: JUMPDEST 00000215: PUSH2 0x021c 00000218: PUSH2 0x02d0 0000021b: JUMP 0000021c: JUMPDEST 0000021d: PUSH1 0x01 0000021f: PUSH1 0x01 00000221: PUSH1 0xa0 00000223: SHL 00000224: SUB 00000225: AND 00000226: CALLER 00000227: SUB 00000228: PUSH2 0x00e1 0000022b: JUMPI 0000022c: PUSH1 0x40 0000022e: MLOAD 0000022f: PUSH3 0x461bcd 00000233: PUSH1 0xe5 00000235: SHL 00000236: DUP2 00000237: MSTORE 00000238: PUSH1 0x20 0000023a: PUSH1 0x04 0000023c: DUP3 0000023d: ADD 0000023e: MSTORE 0000023f: PUSH1 0x42 00000241: PUSH1 0x24 00000243: DUP3 00000244: ADD 00000245: MSTORE 00000246: PUSH32 0x5472616e73706172656e745570677261646561626c6550726f78793a2061646d 00000267: PUSH1 0x44 00000269: DUP3 0000026a: ADD 0000026b: MSTORE 0000026c: PUSH32 0x696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267 0000028d: PUSH1 0x64 0000028f: DUP3 00000290: ADD 00000291: MSTORE 00000292: PUSH2 0x195d 00000295: PUSH1 0xf2 00000297: SHL 00000298: PUSH1 0x84 0000029a: DUP3 0000029b: ADD 0000029c: MSTORE 0000029d: PUSH1 0xa4 0000029f: ADD 000002a0: JUMPDEST 000002a1: PUSH1 0x40 000002a3: MLOAD 000002a4: DUP1 000002a5: SWAP2 000002a6: SUB 000002a7: SWAP1 000002a8: REVERT 000002a9: JUMPDEST 000002aa: PUSH0 000002ab: PUSH2 0x01b4 000002ae: PUSH2 0x038a 000002b1: JUMP 000002b2: JUMPDEST 000002b3: CALLDATASIZE 000002b4: PUSH0 000002b5: DUP1 000002b6: CALLDATACOPY 000002b7: PUSH0 000002b8: DUP1 000002b9: CALLDATASIZE 000002ba: PUSH0 000002bb: DUP5 000002bc: GAS 000002bd: DELEGATECALL 000002be: RETURNDATASIZE 000002bf: PUSH0 000002c0: DUP1 000002c1: RETURNDATACOPY 000002c2: DUP1 000002c3: DUP1 000002c4: ISZERO 000002c5: PUSH2 0x02cc 000002c8: JUMPI 000002c9: RETURNDATASIZE 000002ca: PUSH0 000002cb: RETURN 000002cc: JUMPDEST 000002cd: RETURNDATASIZE 000002ce: PUSH0 000002cf: REVERT 000002d0: JUMPDEST 000002d1: PUSH0 000002d2: PUSH32 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 000002f3: JUMPDEST 000002f4: SLOAD 000002f5: PUSH1 0x01 000002f7: PUSH1 0x01 000002f9: PUSH1 0xa0 000002fb: SHL 000002fc: SUB 000002fd: AND 000002fe: SWAP2 000002ff: SWAP1 00000300: POP 00000301: JUMP 00000302: JUMPDEST 00000303: CALLVALUE 00000304: ISZERO 00000305: PUSH2 0x00e1 00000308: JUMPI 00000309: PUSH0 0000030a: DUP1 0000030b: REVERT 0000030c: JUMPDEST 0000030d: PUSH2 0x0315 00000310: DUP4 00000311: PUSH2 0x03b1 00000314: JUMP 00000315: JUMPDEST 00000316: PUSH0 00000317: DUP3 00000318: MLOAD 00000319: GT 0000031a: DUP1 0000031b: PUSH2 0x0321 0000031e: JUMPI 0000031f: POP 00000320: DUP1 00000321: JUMPDEST 00000322: ISZERO 00000323: PUSH2 0x017f 00000326: JUMPI 00000327: PUSH2 0x0330 0000032a: DUP4 0000032b: DUP4 0000032c: PUSH2 0x03f0 0000032f: JUMP 00000330: JUMPDEST 00000331: POP 00000332: POP 00000333: POP 00000334: POP 00000335: JUMP 00000336: JUMPDEST 00000337: PUSH32 0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f 00000358: PUSH2 0x035f 0000035b: PUSH2 0x02d0 0000035e: JUMP 0000035f: JUMPDEST 00000360: PUSH1 0x40 00000362: DUP1 00000363: MLOAD 00000364: PUSH1 0x01 00000366: PUSH1 0x01 00000368: PUSH1 0xa0 0000036a: SHL 0000036b: SUB 0000036c: SWAP3 0000036d: DUP4 0000036e: AND 0000036f: DUP2 00000370: MSTORE 00000371: SWAP2 00000372: DUP5 00000373: AND 00000374: PUSH1 0x20 00000376: DUP4 00000377: ADD 00000378: MSTORE 00000379: ADD 0000037a: PUSH1 0x40 0000037c: MLOAD 0000037d: DUP1 0000037e: SWAP2 0000037f: SUB 00000380: SWAP1 00000381: LOG1 00000382: PUSH2 0x011b 00000385: DUP2 00000386: PUSH2 0x041c 00000389: JUMP 0000038a: JUMPDEST 0000038b: PUSH0 0000038c: PUSH32 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc 000003ad: PUSH2 0x02f3 000003b0: JUMP 000003b1: JUMPDEST 000003b2: PUSH2 0x03ba 000003b5: DUP2 000003b6: PUSH2 0x04c5 000003b9: JUMP 000003ba: JUMPDEST 000003bb: PUSH1 0x40 000003bd: MLOAD 000003be: PUSH1 0x01 000003c0: PUSH1 0x01 000003c2: PUSH1 0xa0 000003c4: SHL 000003c5: SUB 000003c6: DUP3 000003c7: AND 000003c8: SWAP1 000003c9: PUSH32 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b 000003ea: SWAP1 000003eb: PUSH0 000003ec: SWAP1 000003ed: LOG2 000003ee: POP 000003ef: JUMP 000003f0: JUMPDEST 000003f1: PUSH1 0x60 000003f3: PUSH2 0x0415 000003f6: DUP4 000003f7: DUP4 000003f8: PUSH1 0x40 000003fa: MLOAD 000003fb: DUP1 000003fc: PUSH1 0x60 000003fe: ADD 000003ff: PUSH1 0x40 00000401: MSTORE 00000402: DUP1 00000403: PUSH1 0x27 00000405: DUP2 00000406: MSTORE 00000407: PUSH1 0x20 00000409: ADD 0000040a: PUSH2 0x0799 0000040d: PUSH1 0x27 0000040f: SWAP2 00000410: CODECOPY 00000411: PUSH2 0x0559 00000414: JUMP 00000415: JUMPDEST 00000416: SWAP4 00000417: SWAP3 00000418: POP 00000419: POP 0000041a: POP 0000041b: JUMP 0000041c: JUMPDEST 0000041d: PUSH1 0x01 0000041f: PUSH1 0x01 00000421: PUSH1 0xa0 00000423: SHL 00000424: SUB 00000425: DUP2 00000426: AND 00000427: PUSH2 0x0481 0000042a: JUMPI 0000042b: PUSH1 0x40 0000042d: MLOAD 0000042e: PUSH3 0x461bcd 00000432: PUSH1 0xe5 00000434: SHL 00000435: DUP2 00000436: MSTORE 00000437: PUSH1 0x20 00000439: PUSH1 0x04 0000043b: DUP3 0000043c: ADD 0000043d: MSTORE 0000043e: PUSH1 0x26 00000440: PUSH1 0x24 00000442: DUP3 00000443: ADD 00000444: MSTORE 00000445: PUSH32 0x455243313936373a206e65772061646d696e20697320746865207a65726f2061 00000466: PUSH1 0x44 00000468: DUP3 00000469: ADD 0000046a: MSTORE 0000046b: PUSH6 0x646472657373 00000472: PUSH1 0xd0 00000474: SHL 00000475: PUSH1 0x64 00000477: DUP3 00000478: ADD 00000479: MSTORE 0000047a: PUSH1 0x84 0000047c: ADD 0000047d: PUSH2 0x02a0 00000480: JUMP 00000481: JUMPDEST 00000482: DUP1 00000483: PUSH32 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 000004a4: JUMPDEST 000004a5: DUP1 000004a6: SLOAD 000004a7: PUSH1 0x01 000004a9: PUSH1 0x01 000004ab: PUSH1 0xa0 000004ad: SHL 000004ae: SUB 000004af: NOT 000004b0: AND 000004b1: PUSH1 0x01 000004b3: PUSH1 0x01 000004b5: PUSH1 0xa0 000004b7: SHL 000004b8: SUB 000004b9: SWAP3 000004ba: SWAP1 000004bb: SWAP3 000004bc: AND 000004bd: SWAP2 000004be: SWAP1 000004bf: SWAP2 000004c0: OR 000004c1: SWAP1 000004c2: SSTORE 000004c3: POP 000004c4: JUMP 000004c5: JUMPDEST 000004c6: PUSH1 0x01 000004c8: PUSH1 0x01 000004ca: PUSH1 0xa0 000004cc: SHL 000004cd: SUB 000004ce: DUP2 000004cf: AND 000004d0: EXTCODESIZE 000004d1: PUSH2 0x0532 000004d4: JUMPI 000004d5: PUSH1 0x40 000004d7: MLOAD 000004d8: PUSH3 0x461bcd 000004dc: PUSH1 0xe5 000004de: SHL 000004df: DUP2 000004e0: MSTORE 000004e1: PUSH1 0x20 000004e3: PUSH1 0x04 000004e5: DUP3 000004e6: ADD 000004e7: MSTORE 000004e8: PUSH1 0x2d 000004ea: PUSH1 0x24 000004ec: DUP3 000004ed: ADD 000004ee: MSTORE 000004ef: PUSH32 0x455243313936373a206e657720696d706c656d656e746174696f6e206973206e 00000510: PUSH1 0x44 00000512: DUP3 00000513: ADD 00000514: MSTORE 00000515: PUSH13 0x1bdd08184818dbdb9d1c9858dd 00000523: PUSH1 0x9a 00000525: SHL 00000526: PUSH1 0x64 00000528: DUP3 00000529: ADD 0000052a: MSTORE 0000052b: PUSH1 0x84 0000052d: ADD 0000052e: PUSH2 0x02a0 00000531: JUMP 00000532: JUMPDEST 00000533: DUP1 00000534: PUSH32 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc 00000555: PUSH2 0x04a4 00000558: JUMP 00000559: JUMPDEST 0000055a: PUSH1 0x60 0000055c: PUSH0 0000055d: DUP1 0000055e: DUP6 0000055f: PUSH1 0x01 00000561: PUSH1 0x01 00000563: PUSH1 0xa0 00000565: SHL 00000566: SUB 00000567: AND 00000568: DUP6 00000569: PUSH1 0x40 0000056b: MLOAD 0000056c: PUSH2 0x0575 0000056f: SWAP2 00000570: SWAP1 00000571: PUSH2 0x074b 00000574: JUMP 00000575: JUMPDEST 00000576: PUSH0 00000577: PUSH1 0x40 00000579: MLOAD 0000057a: DUP1 0000057b: DUP4 0000057c: SUB 0000057d: DUP2 0000057e: DUP6 0000057f: GAS 00000580: DELEGATECALL 00000581: SWAP2 00000582: POP 00000583: POP 00000584: RETURNDATASIZE 00000585: DUP1 00000586: PUSH0 00000587: DUP2 00000588: EQ 00000589: PUSH2 0x05ad 0000058c: JUMPI 0000058d: PUSH1 0x40 0000058f: MLOAD 00000590: SWAP2 00000591: POP 00000592: PUSH1 0x1f 00000594: NOT 00000595: PUSH1 0x3f 00000597: RETURNDATASIZE 00000598: ADD 00000599: AND 0000059a: DUP3 0000059b: ADD 0000059c: PUSH1 0x40 0000059e: MSTORE 0000059f: RETURNDATASIZE 000005a0: DUP3 000005a1: MSTORE 000005a2: RETURNDATASIZE 000005a3: PUSH0 000005a4: PUSH1 0x20 000005a6: DUP5 000005a7: ADD 000005a8: RETURNDATACOPY 000005a9: PUSH2 0x05b2 000005ac: JUMP 000005ad: JUMPDEST 000005ae: PUSH1 0x60 000005b0: SWAP2 000005b1: POP 000005b2: JUMPDEST 000005b3: POP 000005b4: SWAP2 000005b5: POP 000005b6: SWAP2 000005b7: POP 000005b8: PUSH2 0x05c3 000005bb: DUP7 000005bc: DUP4 000005bd: DUP4 000005be: DUP8 000005bf: PUSH2 0x05cd 000005c2: JUMP 000005c3: JUMPDEST 000005c4: SWAP7 000005c5: SWAP6 000005c6: POP 000005c7: POP 000005c8: POP 000005c9: POP 000005ca: POP 000005cb: POP 000005cc: JUMP 000005cd: JUMPDEST 000005ce: PUSH1 0x60 000005d0: DUP4 000005d1: ISZERO 000005d2: PUSH2 0x063b 000005d5: JUMPI 000005d6: DUP3 000005d7: MLOAD 000005d8: PUSH0 000005d9: SUB 000005da: PUSH2 0x0634 000005dd: JUMPI 000005de: PUSH1 0x01 000005e0: PUSH1 0x01 000005e2: PUSH1 0xa0 000005e4: SHL 000005e5: SUB 000005e6: DUP6 000005e7: AND 000005e8: EXTCODESIZE 000005e9: PUSH2 0x0634 000005ec: JUMPI 000005ed: PUSH1 0x40 000005ef: MLOAD 000005f0: PUSH3 0x461bcd 000005f4: PUSH1 0xe5 000005f6: SHL 000005f7: DUP2 000005f8: MSTORE 000005f9: PUSH1 0x20 000005fb: PUSH1 0x04 000005fd: DUP3 000005fe: ADD 000005ff: MSTORE 00000600: PUSH1 0x1d 00000602: PUSH1 0x24 00000604: DUP3 00000605: ADD 00000606: MSTORE 00000607: PUSH32 0x416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000 00000628: PUSH1 0x44 0000062a: DUP3 0000062b: ADD 0000062c: MSTORE 0000062d: PUSH1 0x64 0000062f: ADD 00000630: PUSH2 0x02a0 00000633: JUMP 00000634: JUMPDEST 00000635: POP 00000636: DUP2 00000637: PUSH2 0x0645 0000063a: JUMP 0000063b: JUMPDEST 0000063c: PUSH2 0x0645 0000063f: DUP4 00000640: DUP4 00000641: PUSH2 0x064d 00000644: JUMP 00000645: JUMPDEST 00000646: SWAP5 00000647: SWAP4 00000648: POP 00000649: POP 0000064a: POP 0000064b: POP 0000064c: JUMP 0000064d: JUMPDEST 0000064e: DUP2 0000064f: MLOAD 00000650: ISZERO 00000651: PUSH2 0x065d 00000654: JUMPI 00000655: DUP2 00000656: MLOAD 00000657: DUP1 00000658: DUP4 00000659: PUSH1 0x20 0000065b: ADD 0000065c: REVERT 0000065d: JUMPDEST 0000065e: DUP1 0000065f: PUSH1 0x40 00000661: MLOAD 00000662: PUSH3 0x461bcd 00000666: PUSH1 0xe5 00000668: SHL 00000669: DUP2 0000066a: MSTORE 0000066b: PUSH1 0x04 0000066d: ADD 0000066e: PUSH2 0x02a0 00000671: SWAP2 00000672: SWAP1 00000673: PUSH2 0x0766 00000676: JUMP 00000677: JUMPDEST 00000678: DUP1 00000679: CALLDATALOAD 0000067a: PUSH1 0x01 0000067c: PUSH1 0x01 0000067e: PUSH1 0xa0 00000680: SHL 00000681: SUB 00000682: DUP2 00000683: AND 00000684: DUP2 00000685: EQ 00000686: PUSH2 0x068d 00000689: JUMPI 0000068a: PUSH0 0000068b: DUP1 0000068c: REVERT 0000068d: JUMPDEST 0000068e: SWAP2 0000068f: SWAP1 00000690: POP 00000691: JUMP 00000692: JUMPDEST 00000693: PUSH0 00000694: PUSH1 0x20 00000696: DUP3 00000697: DUP5 00000698: SUB 00000699: SLT 0000069a: ISZERO 0000069b: PUSH2 0x06a2 0000069e: JUMPI 0000069f: PUSH0 000006a0: DUP1 000006a1: REVERT 000006a2: JUMPDEST 000006a3: PUSH2 0x0415 000006a6: DUP3 000006a7: PUSH2 0x0677 000006aa: JUMP 000006ab: JUMPDEST 000006ac: PUSH0 000006ad: DUP1 000006ae: PUSH0 000006af: PUSH1 0x40 000006b1: DUP5 000006b2: DUP7 000006b3: SUB 000006b4: SLT 000006b5: ISZERO 000006b6: PUSH2 0x06bd 000006b9: JUMPI 000006ba: PUSH0 000006bb: DUP1 000006bc: REVERT 000006bd: JUMPDEST 000006be: PUSH2 0x06c6 000006c1: DUP5 000006c2: PUSH2 0x0677 000006c5: JUMP 000006c6: JUMPDEST 000006c7: SWAP3 000006c8: POP 000006c9: PUSH1 0x20 000006cb: DUP5 000006cc: ADD 000006cd: CALLDATALOAD 000006ce: PUSH8 0xffffffffffffffff 000006d7: DUP2 000006d8: GT 000006d9: ISZERO 000006da: PUSH2 0x06e1 000006dd: JUMPI 000006de: PUSH0 000006df: DUP1 000006e0: REVERT 000006e1: JUMPDEST 000006e2: DUP5 000006e3: ADD 000006e4: PUSH1 0x1f 000006e6: DUP2 000006e7: ADD 000006e8: DUP7 000006e9: SGT 000006ea: PUSH2 0x06f1 000006ed: JUMPI 000006ee: PUSH0 000006ef: DUP1 000006f0: REVERT 000006f1: JUMPDEST 000006f2: DUP1 000006f3: CALLDATALOAD 000006f4: PUSH8 0xffffffffffffffff 000006fd: DUP2 000006fe: GT 000006ff: ISZERO 00000700: PUSH2 0x0707 00000703: JUMPI 00000704: PUSH0 00000705: DUP1 00000706: REVERT 00000707: JUMPDEST 00000708: DUP7 00000709: PUSH1 0x20 0000070b: DUP3 0000070c: DUP5 0000070d: ADD 0000070e: ADD 0000070f: GT 00000710: ISZERO 00000711: PUSH2 0x0718 00000714: JUMPI 00000715: PUSH0 00000716: DUP1 00000717: REVERT 00000718: JUMPDEST 00000719: SWAP4 0000071a: SWAP7 0000071b: PUSH1 0x20 0000071d: SWAP2 0000071e: SWAP1 0000071f: SWAP2 00000720: ADD 00000721: SWAP6 00000722: POP 00000723: SWAP3 00000724: SWAP4 00000725: POP 00000726: POP 00000727: POP 00000728: JUMP 00000729: JUMPDEST 0000072a: PUSH0 0000072b: JUMPDEST 0000072c: DUP4 0000072d: DUP2 0000072e: LT 0000072f: ISZERO 00000730: PUSH2 0x0743 00000733: JUMPI 00000734: DUP2 00000735: DUP2 00000736: ADD 00000737: MLOAD 00000738: DUP4 00000739: DUP3 0000073a: ADD 0000073b: MSTORE 0000073c: PUSH1 0x20 0000073e: ADD 0000073f: PUSH2 0x072b 00000742: JUMP 00000743: JUMPDEST 00000744: POP 00000745: POP 00000746: PUSH0 00000747: SWAP2 00000748: ADD 00000749: MSTORE 0000074a: JUMP 0000074b: JUMPDEST 0000074c: PUSH0 0000074d: DUP3 0000074e: MLOAD 0000074f: PUSH2 0x075c 00000752: DUP2 00000753: DUP5 00000754: PUSH1 0x20 00000756: DUP8 00000757: ADD 00000758: PUSH2 0x0729 0000075b: JUMP 0000075c: JUMPDEST 0000075d: SWAP2 0000075e: SWAP1 0000075f: SWAP2 00000760: ADD 00000761: SWAP3 00000762: SWAP2 00000763: POP 00000764: POP 00000765: JUMP 00000766: JUMPDEST 00000767: PUSH1 0x20 00000769: DUP2 0000076a: MSTORE 0000076b: PUSH0 0000076c: DUP3 0000076d: MLOAD 0000076e: DUP1 0000076f: PUSH1 0x20 00000771: DUP5 00000772: ADD 00000773: MSTORE 00000774: PUSH2 0x0784 00000777: DUP2 00000778: PUSH1 0x40 0000077a: DUP6 0000077b: ADD 0000077c: PUSH1 0x20 0000077e: DUP8 0000077f: ADD 00000780: PUSH2 0x0729 00000783: JUMP 00000784: JUMPDEST 00000785: PUSH1 0x1f 00000787: ADD 00000788: PUSH1 0x1f 0000078a: NOT 0000078b: AND 0000078c: SWAP2 0000078d: SWAP1 0000078e: SWAP2 0000078f: ADD 00000790: PUSH1 0x40 00000792: ADD 00000793: SWAP3 00000794: SWAP2 00000795: POP 00000796: POP 00000797: JUMP 00000798: INVALID 00000799: COINBASE 0000079a: PUSH5 0x6472657373 000007a0: GASPRICE 000007a1: KECCAK256 000007a2: PUSH13 0x6f772d6c6576656c2064656c65 000007b0: PUSH8 0x6174652063616c6c 000007b9: KECCAK256 000007ba: PUSH7 0x61696c6564a264 000007c2: PUSH10 0x706673582212200877dd 000007cd: SELFBALANCE 000007ce: BASEFEE 000007cf: ADDRESS 000007d0: UNKNOWN(0xF7) 000007d1: ADD 000007d2: PUSH4 0xc455fb72 000007d7: JUMPDEST 000007d8: SWAP12 000007d9: UNKNOWN(0xE6) 000007da: LOG4 000007db: PUSH15 0x5898136c0dea5007a60f1c01544a64 000007eb: PUSH20
| Severity | Category | Tool | Title | Confidence | Validated | Confirmed | Details |
|---|---|---|---|---|---|---|---|
| critical | upgradeability | detector | Untrusted DELEGATECALL target reachable | 70 | no | no |
viewtrace_id: 0x1bfc246ef69e1617b5b75cb156a7c2ed64440b69b36a72cc977aee5983a41c88
call_targets:
0x62c9e5e52351e02635f48072fa20c03bb650f787
target_varies:
no
classification:
constant_target
validation_json{
"sink": "DELEGATECALL",
"errors": 0,
"status": "sink_reached",
"attempts": 2,
"trace_id": "0x1bfc246ef69e1617b5b75cb156a7c2ed64440b69b36a72cc977aee5983a41c88",
"confirmed": false,
"trace_mode": "callTracer",
"call_targets": [
"0x62c9e5e52351e02635f48072fa20c03bb650f787"
],
"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": "0x3659cfe6",
"selector": "0x3659cfe6",
"calldata_variants": [
"0x3659cfe6",
"0x3659cfe60000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x4f1ef286",
"selector": "0x4f1ef286",
"calldata_variants": [
"0x4f1ef286",
"0x4f1ef2860000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x5c60da1b",
"selector": "0x5c60da1b",
"calldata_variants": [
"0x5c60da1b",
"0x5c60da1b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8f283970",
"selector": "0x8f283970",
"calldata_variants": [
"0x8f283970",
"0x8f2839700000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf851a440",
"selector": "0xf851a440",
"calldata_variants": [
"0xf851a440",
"0xf851a4400000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 701,
"opcode": "DELEGATECALL",
"returndata_checked": null,
"value_expression_category": "n/a",
"target_expression_category": "computed"
},
{
"pc": 1408,
"opcode": "DELEGATECALL",
"returndata_checked": null,
"value_expression_category": "n/a",
"target_expression_category": "computed"
}
],
"guards_detected": [],
"delegatecall_count": 2,
"untrusted_delegatecall_count": 2
}
|
| medium | upgradeability | cast | DELEGATECALL present | 80 | no | — |
viewevidence_json{
"notes": "delegatecall enables execution in caller context; common in proxies/upgradeable patterns",
"delegatecall_count": 2
}
|
| medium | access_control | codex | Computed DELEGATECALL target reachable via selector 0xf62d1888 | 75 | no | — |
viewevidence_json{
"evidence": "detector_findings reports untrusted_delegatecall_count=1 with computed target at pc 3653 (0x0e45) and no guards detected; disassembly shows DELEGATECALL at pc 0x0e45 in selector 0xf62d1888.",
"locations": [
"selector:0xf62d1888",
"pc:0x0e45"
],
"recommendation": "Ensure the DELEGATECALL path is gated by explicit authorization (owner/role/entrypoint) on all branches, or restrict the delegatecall target to a fixed allowlist (ideally self). Consider emitting explicit errors when unauthorized to make analysis/monitoring easier.",
"exploit_scenario": "The function at selector 0xf62d1888 reaches a DELEGATECALL (pc:0x0e45) where the target is computed from calldata. If an untrusted caller can invoke this path without strict authorization, they can execute arbitrary code in the contract\u2019s storage context, corrupting state or draining funds held by the proxy/implementation."
}
|
| medium | access_control | codex | Arbitrary external CALL (with ETH value) reachable via selector 0xf62d1888 | 75 | no | — |
viewevidence_json{
"evidence": "detector_findings show untrusted_call_count=7 and eth_value_calls=7 with computed targets/values; callsites include pc 2149 (0x0865), 5006 (0x138e), 10448 (0x28d0), 11101 (0x2b5d), 11590 (0x2d46), 12363 (0x304b).",
"locations": [
"selector:0xf62d1888",
"pc:0x0865",
"pc:0x138e",
"pc:0x28d0",
"pc:0x2b5d",
"pc:0x2d46",
"pc:0x304b"
],
"recommendation": "Confirm that all CALL paths are protected by strong authorization checks (owner/signature/role). If the intent is limited execution, validate targets/values and consider reentrancy protections around state updates that follow external calls.",
"exploit_scenario": "Selector 0xf62d1888 reaches multiple CALL sites (pc:0x0865/0x138e/0x28d0/0x2b5d/0x2d46/0x304b) where both target and value are computed. If these paths are accessible to untrusted callers, they can initiate arbitrary external calls and transfer ETH or tokens, effectively turning the contract into a publicly callable execution proxy."
}
|