019bb50b-e183-704b-ae79-33466bc022ff
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 |
|---|---|---|---|---|
| 40401 | artifact.fetch | complete | 1 / 3 | 3 months ago |
| 40402 | proxy.resolve | complete | 1 / 3 | 3 months ago |
| 40403 | tool.cast_disasm | complete | 1 / 3 | 3 months ago |
| 40404 | analysis.bundle | complete | 1 / 3 | 3 months ago |
| 40405 | capability.graph | complete | 1 / 3 | 3 months ago |
| 40406 | detector.run | complete | 1 / 3 | 3 months ago |
| 40407 | validation.fork | complete | 1 / 3 | 3 months ago |
| 40497 | report.consolidate | complete | 1 / 6 | 3 months ago |
{
"status": "not_proxy"
}
No slither job recorded yet.
{"no_findings":false,"summary":"Detected fixed-stipend ETH transfers via low-level CALLs; this pattern can brick withdrawals for contract recipients or after gas schedule changes.","findings":[{"severity":"low","category":"other","title":"Fixed 2300-gas ETH transfers can make withdrawals revert for contract recipients","exploit_scenario":"If the beneficiary/owner address is a contract with a receive/fallback that needs more than the 2300 gas stipend (or gas costs increase), the CALL will fail and revert the withdrawal, potentially leaving ETH locked. This is inferred from bytecode and could be a false positive if an alternate withdrawal path exists.","recommendation":"Use `call{value: amount}(\"\")` with full gas forwarding and protect with checks-effects-interactions or a reentrancy guard, or add an alternative withdrawal path / configurable gas stipend.","evidence":"Bytecode shows `PUSH2 0x08fc` (2300) immediately before low-level CALLs that transfer value; CALL opcodes at pc 0x3dd and 0x8af.","locations":["pc:0x3dd","pc:0x8af","pc:0x3ae","pc:0x897"]}]}
OpenAI Codex v0.77.0 (research preview)
--------
workdir: /tmp/codex-qbgy8ng7
model: gpt-5.2-codex
provider: openai
approval: never
sandbox: read-only
reasoning effort: high
reasoning summaries: auto
session id: 019bb52f-8f6a-76c2-81c5-683ab0c4207b
--------
user
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
**Reading BYTECODE_BUNDLE.json**
exec
/bin/bash -lc ls in /tmp/codex-qbgy8ng7 succeeded in 6ms:
BYTECODE_BUNDLE.json
codex-output-schema.json
exec
/bin/bash -lc 'cat BYTECODE_BUNDLE.json' in /tmp/codex-qbgy8ng7 succeeded in 32ms:
{
"analysis_artifact": {
"address": "0x91bf99ca34268d407f3cc8d6525ce83c6ea7bcf5",
"artifact_hash": "0x0130a0dc383ef1075821d32fc78764b732fafc238a74e0573b26e65e3b97b1bf",
"artifact_json": {
"auth": {
"guards": [
{
"pc": 719,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
},
{
"pc": 1102,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
},
{
"pc": 1407,
"type": "msg_sender_eq_const",
thinking
**Analyzing bytecode for call patterns and access controls**
I'm parsing bytecode to understand CALL and CALLCODE usage, noting legacy delegatecall patterns and unusual guards that restrict access to a hardcoded max address. This might represent an uninitialized admin, which isn't a direct vulnerability but could lead to stuck privileges. I’m focusing on identifying ownership functions, external calls that may allow reentrancy, and scanning for proxy upgrade patterns like EIP-1967, planning to search the storage slots in the evidence JSON using ripgrep next.
exec
/bin/bash -lc 'rg -n "storage" BYTECODE_BUNDLE.json' in /tmp/codex-qbgy8ng7 succeeded in 37ms:
2361: "storage": {
2471: "storage": {
2581: "storage": {
2691: "storage": {
2801: "storage": {
2911: "storage": {
3021: "storage": {
3131: "storage": {
3241: "storage": {
3351: "storage": {
3450: "storage": {
thinking
**Checking storage-related sections**
exec
/bin/bash -lc "sed -n '3440,3520p' BYTECODE_BUNDLE.json" in /tmp/codex-qbgy8ng7 succeeded in 8ms:
],
"sinks": {
"call": 3,
"create": 0,
"create2": 0,
"delegatecall": 0,
"selfdestruct": 0,
"staticcall": 0,
"upgrade_slot_write_suspected": false
},
"storage": {
"keccak_count": 6,
"reads": 19,
"slots": [
{
"op": "SLOAD",
"pc": 667,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
exec
/bin/bash -lc "sed -n '3520,3600p' BYTECODE_BUNDLE.json" in /tmp/codex-qbgy8ng7 succeeded in 6ms:
"op": "SLOAD",
"pc": 2007,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000014"
}
],
"writes": 5
},
"version": "analysis_artifact_v1"
},
"block_number": null,
"chain_id": 1,
"codehash": "0x6c3033a50581715bc0c0994bfc99a9f8ed08266255de4fad01c0abfa2d784765",
"created_at": "2026-01-13T01:50:51.000000Z",
"id": 1118,
"updated_at": "2026-01-13T01:50:51.000000Z",
"version": "analysis_artifact_v1"
},
"analysis_run": {
"address": "0x91bf99ca34268d407f3cc8d6525ce83c6ea7bcf5",
"block_number": null,
thinking
**Analyzing runtime bytecode for calls and ownership**
I'm examining the runtime bytecode to identify ownership patterns and call instructions, focusing on slots storing owner and status. I'm investigating whether CALL instructions target the contract itself, suggesting internal ETH transfers, and planning to parse the bytecode around CALL opcodes using Python tooling despite a limited environment.
exec
/bin/bash -lc "python - <<'PY'
import json, binascii
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
bytecode=data['artifact']['runtime_bytecode']['full']
if bytecode.startswith('0x'):
bytecode=bytecode[2:]
code=bytes.fromhex(bytecode)
# find CALL (0xf1) and CALLCODE (0xf2)
for opc,name in [(0xf1,'CALL'),(0xf2,'CALLCODE')]:
idxs=[i for i,b in enumerate(code) if b==opc]
print(name,idxs)
for i in idxs:
start=max(0,i-20)
end=min(len(code), i+20)
snippet=code[start:end]
print(i, snippet.hex())
PY" in /tmp/codex-qbgy8ng7 succeeded in 26ms:
CALL [747, 989, 2223]
747 ffffffffffffffffffffffffffff161415156102f157600080fd5b600060028111156102fe57fe5b
989 9081150290604051600060405180830381858888f1935050505015156103ed57600080fd5b565b60
2223 9081150290604051600060405180830381858888f1935050505015156108bf57600080fd5b8173ff
CALLCODE [122, 1596, 2373]
122 93fb14610172578063cb13cddb146101a9578063f2fde38b146101f6578063f340fa011461022f57
1596 ffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e06040
2373 65627a7a72305820932a3e029fc610e90985300bf26f653d2ece3258ea9eb306c2b0831c4f6fe796
thinking
**Planning precise EVM opcode detection**
I’m figuring out that raw searches for opcodes like 0xf2 can produce false positives since these bytes might appear inside PUSH data. To handle this, I want to build a minimal EVM disassembler that skips PUSH instructions properly so I can accurately identify real CALL and CALLCODE opcode positions rather than mistaken metadata or data bytes. This will help me verify the true locations of these opcodes in the bytecode.
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
code=bytes.fromhex(code[2:])
ops=defaultdict(list)
i=0
while i < len(code):
op=code[i]
ops[op].append(i)
if 0x60 <= op <= 0x7f: # PUSH1..PUSH32
n=op-0x5f
i += 1+n
continue
i += 1
print('CALL', ops[0xf1])
print('CALLCODE', ops[0xf2])
PY" in /tmp/codex-qbgy8ng7 succeeded in 58ms:
CALL [989, 2223]
CALLCODE [2373]
thinking
**Analyzing CALL and CALLCODE opcodes**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=data['artifact']['runtime_bytecode']['full']
code=bytes.fromhex(code[2:])
# simple disassembler
opnames = {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',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
# build mapping pc->(op,imm)
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
name=f'PUSH{n}'
ins.append((i,name,imm))
i += 1+n
continue
name=opnames.get(op, f'OP_{op:02x}')
ins.append((i,name,None))
i += 1
# function to print window around pc
pc_targets=[989,2223,2373]
for target in pc_targets:
print('\\n=== window around',target,'===')
# find index in ins
idx=None
for j,(pc,name,imm) in enumerate(ins):
if pc==target:
idx=j
break
if idx is None:
# find nearest
for j,(pc,_,_) in enumerate(ins):
if pc>target:
idx=j
break
start=max(0,idx-20)
end=min(len(ins), idx+20)
for pc,name,imm in ins[start:end]:
if imm is not None:
print(f'{pc:04d}: {name} 0x{imm.hex()}')
else:
print(f'{pc:04d}: {name}')
PY" in /tmp/codex-qbgy8ng7 succeeded in 34ms:
=== window around 989 ===
0946: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0967: AND
0968: BALANCE
0969: OP_90
0970: OP_81
0971: ISZERO
0972: MUL
0973: OP_90
0974: PUSH1 0x40
0976: MLOAD
0977: PUSH1 0x00
0979: PUSH1 0x40
0981: MLOAD
0982: OP_80
0983: OP_83
0984: SUB
0985: OP_81
0986: OP_85
thinking
**Clarifying callcode presence in metadata**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={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',0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i,f'PUSH{n}',imm))
i += 1+n
continue
ins.append((i,opnames.get(op, f'OP_{op:02x}'),None))
i += 1
# print window around 900-1020
for pc,name,imm in ins:
if 880 <= pc <= 1020:
if imm is not None:
print(f'{pc:04d}: {name} 0x{imm.hex()}')
else:
print(f'{pc:04d}: {name}')
PY" in /tmp/codex-qbgy8ng7 succeeded in 27ms:
0880: OP_80
0881: OP_91
0882: SUB
0883: OP_90
0884: OP_a1
0885: PUSH1 0x02
0887: PUSH1 0x00
0889: OP_90
0890: SLOAD
0891: OP_90
0892: PUSH2 0x0100
0895: EXP
0896: OP_90
0897: DIV
0898: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0919: AND
0920: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0941: AND
0942: PUSH2 0x08fc
0945: ADDRESS
thinking
**Analyzing CALL and storage address extraction**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={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',0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i,f'PUSH{n}',imm))
i += 1+n
continue
ins.append((i,opnames.get(op, f'OP_{op:02x}'),None))
i += 1
for pc,name,imm in ins:
if 2140 <= pc <= 2265:
if imm is not None:
print(f'{pc:04d}: {name} 0x{imm.hex()}')
else:
print(f'{pc:04d}: {name}')
PY" in /tmp/codex-qbgy8ng7 succeeded in 29ms:
2157: AND
2158: OP_81
2159: MSTORE
2160: PUSH1 0x20
2162: ADD
2163: OP_90
2164: OP_81
2165: MSTORE
2166: PUSH1 0x20
2168: ADD
2169: PUSH1 0x00
2171: SHA3
2172: OP_81
2173: OP_90
2174: SSTORE
2175: POP
2176: OP_81
2177: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
2198: AND
2199: PUSH2 0x08fc
thinking
**Requesting earlier code lines**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={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',0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i,f'PUSH{n}',imm))
i += 1+n
continue
ins.append((i,opnames.get(op, f'OP_{op:02x}'),None))
i += 1
for pc,name,imm in ins:
if 2040 <= pc <= 2145:
if imm is not None:
print(f'{pc:04d}: {name} 0x{imm.hex()}')
else:
print(f'{pc:04d}: {name}')
PY" in /tmp/codex-qbgy8ng7 succeeded in 30ms:
2040: JUMPDEST
2041: PUSH1 0x01
2043: PUSH1 0x00
2045: OP_83
2046: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
2067: AND
2068: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
2089: AND
2090: OP_81
2091: MSTORE
2092: PUSH1 0x20
2094: ADD
2095: OP_90
2096: OP_81
2097: MSTORE
2098: PUSH1 0x20
2100: ADD
2101: PUSH1 0x00
2103: SHA3
2104: SLOAD
thinking
**Analyzing runtime bytecode structure**
exec
/bin/bash -lc 'which evm' in /tmp/codex-qbgy8ng7 exited 1 in 28ms:
thinking
**Analyzing potential reentrancy risks**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={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',0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i,f'PUSH{n}',imm))
i += 1+n
continue
ins.append((i,opnames.get(op, f'OP_{op:02x}'),None))
i += 1
for pc,name,imm in ins:
if 700 <= pc <= 900:
if imm is not None:
print(f'{pc:04d}: {name} 0x{imm.hex()}')
else:
print(f'{pc:04d}: {name}')
PY" in /tmp/codex-qbgy8ng7 succeeded in 29ms:
0718: AND
0719: CALLER
0720: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0741: AND
0742: EQ
0743: ISZERO
0744: ISZERO
0745: PUSH2 0x02f1
0748: JUMPI
0749: PUSH1 0x00
0751: OP_80
0752: REVERT
0753: JUMPDEST
0754: PUSH1 0x00
0756: PUSH1 0x02
0758: OP_81
0759: GT
0760: ISZERO
0761: PUSH2 0x02fe
0764: JUMPI
thinking
**Analyzing contract call and guard logic**
thinking
**Investigating withdrawal function logic and access checks**
I’m carefully thinking about how the withdraw function takes an address parameter and handles deposits and withdrawals, noting owner-only deposit rights versus public withdrawal. I’m considering how funds are sent strictly to the specified address, so callers can trigger withdrawals for others but cannot steal funds. Also, I’m examining gas stipend usage in calls (2300 gas), its implications on reentrancy and DoS, and planning a symbolic execution to validate call arguments and stack behavior for better understanding.
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames = {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',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
# disassemble to list
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i, f'PUSH{n}', imm))
i += 1+n
else:
ins.append((i, opnames.get(op,f'OP_{op:02x}'), None))
i += 1
# map pc to index
pc_to_idx={pc:idx for idx,(pc,_,_) in enumerate(ins)}
# simple symbolic stack
class Sym(str):
pass
def popn(stack,n):
if len(stack)<n:
raise Exception('stack underflow')
vals=stack[-n:]
del stack[-n:]
return vals
def push(stack, val):
stack.append(val)
# interpreter from pc 662 until CALL at 989
pc=662
stack=[]
visited=set()
steps=0
while True:
if pc not in pc_to_idx:
print('pc not found',pc);break
idx=pc_to_idx[pc]
op,imm = ins[idx][1], ins[idx][2]
# print each step
# print(f'{pc}: {op} {imm.hex() if imm else \"\"} stack size {len(stack)}')
steps+=1
if steps>2000:
print('too many');break
# handle ops
if op.startswith('PUSH'):
push(stack, f'0x{imm.hex()}')
pc = ins[idx+1][0]
continue
if op=='JUMPDEST':
pc = ins[idx+1][0]
continue
if op=='POP':
popn(stack,1)
pc = ins[idx+1][0]
continue
if op=='CALLER':
push(stack,'CALLER')
pc = ins[idx+1][0]
continue
if op=='ADDRESS':
push(stack,'ADDRESS')
pc = ins[idx+1][0]
continue
if op=='BALANCE':
addr=popn(stack,1)[0]
push(stack,f'BALANCE({addr})')
pc = ins[idx+1][0]
continue
if op=='SLOAD':
slot=popn(stack,1)[0]
push(stack,f'SLOAD({slot})')
pc = ins[idx+1][0]
continue
if op=='SSTORE':
popn(stack,2)
pc = ins[idx+1][0]
continue
if op in ('MLOAD','MSTORE','MSTORE8','CALLDATASIZE','CALLDATALOAD','CALLDATACOPY','CODECOPY','RETURNDATACOPY','RETURNDATASIZE','MSIZE'):
# simplify
if op in ('MSTORE','MSTORE8','CALLDATACOPY','CODECOPY','RETURNDATACOPY'):
# consume args
if op=='MSTORE': popn(stack,2)
elif op=='MSTORE8': popn(stack,2)
elif op=='CALLDATACOPY': popn(stack,3)
elif op=='CODECOPY': popn(stack,3)
elif op=='RETURNDATACOPY': popn(stack,3)
pc = ins[idx+1][0]
continue
if op=='MLOAD':
popn(stack,1)
push(stack,'MLOAD')
pc = ins[idx+1][0]
continue
if op=='CALLDATASIZE':
push(stack,'CALLDATASIZE')
pc = ins[idx+1][0]
continue
if op=='CALLDATALOAD':
popn(stack,1)
push(stack,'CALLDATALOAD')
pc = ins[idx+1][0]
continue
if op=='RETURNDATASIZE':
push(stack,'RETURNDATASIZE')
pc = ins[idx+1][0]
continue
if op=='MSIZE':
push(stack,'MSIZE')
pc = ins[idx+1][0]
continue
# arithmetic/logic
if op in ('ADD','SUB','MUL','DIV','AND','OR','XOR','EQ','LT','GT','ISZERO','EXP'):
if op=='ISZERO':
a=popn(stack,1)[0]
push(stack,f'ISZERO({a})')
else:
b,a=popn(stack,2)
push(stack,f'({a} {op} {b})')
pc = ins[idx+1][0]
continue
if op.startswith('OP_'):
# treat SWAP/DUP via hex? But opnames mapping didn't include DUP/SWAP. Need handle.
# We'll decode dup/swap by opcode value from pc.
opcode=code[pc]
if 0x80 <= opcode <= 0x8f: # DUP1..DUP16
n=opcode-0x7f
if len(stack)<n:
raise Exception('dup underflow')
push(stack, stack[-n])
pc = ins[idx+1][0]
continue
if 0x90 <= opcode <= 0x9f: # SWAP1..SWAP16
n=opcode-0x8f
if len(stack)<n+1:
raise Exception('swap underflow')
stack[-1], stack[-1-n] = stack[-1-n], stack[-1]
pc = ins[idx+1][0]
continue
if op=='JUMPI':
# pop dest and cond
dest,cond=popn(stack,2)
# assume jump taken
try:
pc=int(dest,16) if dest.startswith('0x') else int(dest)
except Exception:
# if dest symbolic, break
print('symbolic dest',dest);break
continue
if op=='JUMP':
dest=popn(stack,1)[0]
try:
pc=int(dest,16) if dest.startswith('0x') else int(dest)
except Exception:
print('symbolic jump dest',dest);break
continue
if op=='REVERT':
break
if op=='CALL':
# print stack snapshot for call args
print('CALL at',pc,'stack (top last):')
for i,v in enumerate(stack[-10:]):
print(i-len(stack), v)
break
# default: advance
pc = ins[idx+1][0]
PY" in /tmp/codex-qbgy8ng7 succeeded in 29ms:
symbolic dest ISZERO(ISZERO(((0xffffffffffffffffffffffffffffffffffffffff AND CALLER) EQ (0xffffffffffffffffffffffffffffffffffffffff AND (0xffffffffffffffffffffffffffffffffffffffff AND (SLOAD(0x00) DIV (0x0100 EXP 0x00)))))))
thinking
**Analyzing JUMPI stack order confusion**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={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',0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
# disassemble
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i,f'PUSH{n}',imm))
i += 1+n
else:
ins.append((i,opnames.get(op,f'OP_{op:02x}'),None))
i += 1
pc_to_idx={pc:idx for idx,(pc,_,_) in enumerate(ins)}
# helper
def popn(stack,n):
vals=stack[-n:]
del stack[-n:]
return vals
def run(start_pc, target_pc):
pc=start_pc
stack=[]
steps=0
while True:
idx=pc_to_idx.get(pc)
if idx is None:
print('pc not found',pc);break
op,imm=ins[idx][1], ins[idx][2]
steps+=1
if steps>3000:
print('too many steps');break
if op.startswith('PUSH'):
stack.append(f'0x{imm.hex()}')
pc=ins[idx+1][0]; continue
if op=='JUMPDEST':
pc=ins[idx+1][0]; continue
if op=='POP':
popn(stack,1); pc=ins[idx+1][0]; continue
if op=='CALLER':
stack.append('CALLER'); pc=ins[idx+1][0]; continue
if op=='ADDRESS':
stack.append('ADDRESS'); pc=ins[idx+1][0]; continue
if op=='BALANCE':
addr=popn(stack,1)[0]; stack.append(f'BALANCE({addr})'); pc=ins[idx+1][0]; continue
if op=='SLOAD':
slot=popn(stack,1)[0]; stack.append(f'SLOAD({slot})'); pc=ins[idx+1][0]; continue
if op=='SSTORE':
popn(stack,2); pc=ins[idx+1][0]; continue
if op in ('MSTORE','MSTORE8','CALLDATACOPY','CODECOPY','RETURNDATACOPY'):
if op=='MSTORE': popn(stack,2)
elif op=='MSTORE8': popn(stack,2)
elif op=='CALLDATACOPY': popn(stack,3)
elif op=='CODECOPY': popn(stack,3)
elif op=='RETURNDATACOPY': popn(stack,3)
pc=ins[idx+1][0]; continue
if op=='MLOAD':
popn(stack,1); stack.append('MLOAD'); pc=ins[idx+1][0]; continue
if op in ('CALLDATASIZE','CALLVALUE'):
stack.append(op); pc=ins[idx+1][0]; continue
if op=='CALLDATALOAD':
popn(stack,1); stack.append('CALLDATALOAD'); pc=ins[idx+1][0]; continue
if op=='RETURNDATASIZE':
stack.append('RETURNDATASIZE'); pc=ins[idx+1][0]; continue
if op=='SHA3':
b,a=popn(stack,2); stack.append(f'SHA3({a},{b})'); pc=ins[idx+1][0]; continue
if op in ('ADD','SUB','MUL','DIV','AND','OR','XOR','EQ','LT','GT','ISZERO','EXP'):
if op=='ISZERO':
a=popn(stack,1)[0]; stack.append(f'ISZERO({a})')
else:
b,a=popn(stack,2); stack.append(f'({a} {op} {b})')
pc=ins[idx+1][0]; continue
# dup/swap
opcode=code[pc]
if 0x80 <= opcode <= 0x8f:
n=opcode-0x7f
stack.append(stack[-n])
pc=ins[idx+1][0]; continue
if 0x90 <= opcode <= 0x9f:
n=opcode-0x8f
stack[-1], stack[-1-n] = stack[-1-n], stack[-1]
pc=ins[idx+1][0]; continue
if op=='JUMPI':
dest_cond=popn(stack,2)
dest=dest_cond[1] # top is dest
# jump taken
try:
pc=int(dest,16)
except Exception:
print('symbolic dest',dest); break
continue
if op=='JUMP':
dest=popn(stack,1)[0]
try:
pc=int(dest,16)
except Exception:
print('symbolic dest',dest); break
continue
if op=='REVERT':
print('revert'); break
if op=='CALL':
print('CALL at',pc)
# print top 7 args
args=stack[-7:]
print('stack top 7 (bottom->top):', args)
break
# default
pc=ins[idx+1][0]
run(662,989)
PY" in /tmp/codex-qbgy8ng7 succeeded in 35ms:
CALL at 989
stack top 7 (bottom->top): ['0x00', 'MLOAD', '(MLOAD SUB MLOAD)', 'MLOAD', 'BALANCE((0xffffffffffffffffffffffffffffffffffffffff AND ADDRESS))', '(0xffffffffffffffffffffffffffffffffffffffff AND (0xffffffffffffffffffffffffffffffffffffffff AND (SLOAD(0x02) DIV (0x0100 EXP 0x00))))', '(ISZERO(BALANCE((0xffffffffffffffffffffffffffffffffffffffff AND ADDRESS))) MUL 0x08fc)']
thinking
**Analyzing CALL argument stack and reentrancy risks**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={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',0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i,f'PUSH{n}',imm))
i += 1+n
else:
ins.append((i,opnames.get(op,f'OP_{op:02x}'),None))
i += 1
for guard_pc in [1102,1407,1748]:
print('\\n-- around',guard_pc,'--')
for pc,name,imm in ins:
if guard_pc-20 <= pc <= guard_pc+20:
if imm is not None:
print(f'{pc:04d}: {name} 0x{imm.hex()}')
else:
print(f'{pc:04d}: {name}')
PY" in /tmp/codex-qbgy8ng7 succeeded in 45ms:
-- around 1102 --
1101: AND
1102: CALLER
1103: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
-- around 1407 --
1406: AND
1407: CALLER
1408: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
-- around 1748 --
1747: AND
1748: CALLER
1749: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
thinking
**Summarizing contract call analysis and risks**
I'm working through the contract's CALL operations, especially low-level ETH transfers using a fixed 2300 gas stipend, which could cause denial-of-service if recipients are contracts needing more gas. I'm noting these transfers happen to computed addresses from storage slots with owner controls, so no clear vulnerability but some residual risk. I'll mention two low-severity findings: risk of stuck funds due to gas limit and potential reentrancy considerations, backing both with precise evidence from callsite locations and instruction patterns.
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={0x55:'SSTORE'}
# disassemble minimal
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
i += 1+n
else:
if op==0x55:
ins.append(i)
i += 1
print('SSTORE PCs:',ins)
PY" in /tmp/codex-qbgy8ng7 succeeded in 53ms:
SSTORE PCs: [839, 1223, 1687, 1982, 2174]
thinking
**Inspecting SSTORE instructions and surrounding code**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={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',0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i,f'PUSH{n}',imm))
i += 1+n
else:
ins.append((i,opnames.get(op,f'OP_{op:02x}'),None))
i += 1
for target in [1223,1687,1982,2174,839]:
print('\\n-- window around',target,'--')
for pc,name,imm in ins:
if target-12 <= pc <= target+12:
if imm is not None:
print(f'{pc:04d}: {name} 0x{imm.hex()}')
else:
print(f'{pc:04d}: {name}')
PY" in /tmp/codex-qbgy8ng7 succeeded in 47ms:
-- window around 1223 --
1211: OP_81
1212: GT
1213: ISZERO
1214: PUSH2 0x04c3
1217: JUMPI
1218: INVALID
1219: JUMPDEST
1220: MUL
1221: OR
1222: OP_90
1223: SSTORE
1224: POP
1225: PUSH32 0x599d8e5a83cffb867d051598c4d70e805d59802d8081c1c7d6dffc5b6aca2b89
-- window around 1687 --
1683: AND
1684: MUL
1685: OR
thinking
**Evaluating call arguments and gas constants**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={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',0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
# disassemble
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
ins.append((i,f'PUSH{n}',imm))
i += 1+n
else:
ins.append((i,opnames.get(op,f'OP_{op:02x}'),None))
i += 1
pc_to_idx={pc:idx for idx,(pc,_,_) in enumerate(ins)}
# interpreter similar to before
def popn(stack,n):
vals=stack[-n:]
del stack[-n:]
return vals
pc=2040
stack=[]
steps=0
while True:
idx=pc_to_idx.get(pc)
if idx is None:
print('pc not found',pc); break
op,imm=ins[idx][1], ins[idx][2]
steps+=1
if steps>3000:
print('too many steps'); break
if op.startswith('PUSH'):
stack.append(f'0x{imm.hex()}'); pc=ins[idx+1][0]; continue
if op=='JUMPDEST':
pc=ins[idx+1][0]; continue
if op=='POP':
popn(stack,1); pc=ins[idx+1][0]; continue
if op=='CALLER':
stack.append('CALLER'); pc=ins[idx+1][0]; continue
if op=='ADDRESS':
stack.append('ADDRESS'); pc=ins[idx+1][0]; continue
if op=='BALANCE':
addr=popn(stack,1)[0]; stack.append(f'BALANCE({addr})'); pc=ins[idx+1][0]; continue
if op=='SLOAD':
slot=popn(stack,1)[0]; stack.append(f'SLOAD({slot})'); pc=ins[idx+1][0]; continue
if op=='SSTORE':
popn(stack,2); pc=ins[idx+1][0]; continue
if op in ('MSTORE','MSTORE8','CALLDATACOPY','CODECOPY','RETURNDATACOPY'):
if op=='MSTORE': popn(stack,2)
elif op=='MSTORE8': popn(stack,2)
elif op=='CALLDATACOPY': popn(stack,3)
elif op=='CODECOPY': popn(stack,3)
elif op=='RETURNDATACOPY': popn(stack,3)
pc=ins[idx+1][0]; continue
if op=='MLOAD':
popn(stack,1); stack.append('MLOAD'); pc=ins[idx+1][0]; continue
if op in ('CALLDATASIZE','CALLVALUE'):
stack.append(op); pc=ins[idx+1][0]; continue
if op=='CALLDATALOAD':
popn(stack,1); stack.append('CALLDATALOAD'); pc=ins[idx+1][0]; continue
if op=='RETURNDATASIZE':
stack.append('RETURNDATASIZE'); pc=ins[idx+1][0]; continue
if op=='SHA3':
b,a=popn(stack,2); stack.append(f'SHA3({a},{b})'); pc=ins[idx+1][0]; continue
if op in ('ADD','SUB','MUL','DIV','AND','OR','XOR','EQ','LT','GT','ISZERO','EXP'):
if op=='ISZERO':
a=popn(stack,1)[0]; stack.append(f'ISZERO({a})')
else:
b,a=popn(stack,2); stack.append(f'({a} {op} {b})')
pc=ins[idx+1][0]; continue
opcode=code[pc]
if 0x80 <= opcode <= 0x8f:
n=opcode-0x7f; stack.append(stack[-n]); pc=ins[idx+1][0]; continue
if 0x90 <= opcode <= 0x9f:
n=opcode-0x8f; stack[-1], stack[-1-n] = stack[-1-n], stack[-1]; pc=ins[idx+1][0]; continue
if op=='JUMPI':
dest_cond=popn(stack,2)
dest=dest_cond[1]
try:
pc=int(dest,16)
except Exception:
print('symbolic dest',dest); break
continue
if op=='JUMP':
dest=popn(stack,1)[0]
try:
pc=int(dest,16)
except Exception:
print('symbolic dest',dest); break
continue
if op=='CALL':
print('CALL at',pc)
args=stack[-7:]
print('stack top 7 (bottom->top):', args)
break
if op=='REVERT':
print('revert'); break
pc=ins[idx+1][0]
PY" in /tmp/codex-qbgy8ng7 exited 1 in 46ms:
Traceback (most recent call last):
File "<stdin>", line 82, in <module>
IndexError: list index out of range
thinking
**Analyzing program counter references for calls**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('/tmp/codex-qbgy8ng7/BYTECODE_BUNDLE.json') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
ins=[]
i=0
while i < len(code):
op=code[i]
if 0x60 <= op <= 0x7f:
n=op-0x5f
imm=code[i+1:i+1+n]
if op==0x61 and imm==bytes.fromhex('08fc'):
print('PUSH2 0x08fc at pc',i)
i += 1+n
else:
i += 1
PY" in /tmp/codex-qbgy8ng7 succeeded in 29ms:
PUSH2 0x08fc at pc 942
PUSH2 0x08fc at pc 2199
thinking
**Composing vulnerability JSON report**
codex
{"no_findings":false,"summary":"Detected fixed-stipend ETH transfers via low-level CALLs; this pattern can brick withdrawals for contract recipients or after gas schedule changes.","findings":[{"severity":"low","category":"other","title":"Fixed 2300-gas ETH transfers can make withdrawals revert for contract recipients","exploit_scenario":"If the beneficiary/owner address is a contract with a receive/fallback that needs more than the 2300 gas stipend (or gas costs increase), the CALL will fail and revert the withdrawal, potentially leaving ETH locked. This is inferred from bytecode and could be a false positive if an alternate withdrawal path exists.","recommendation":"Use `call{value: amount}(\"\")` with full gas forwarding and protect with checks-effects-interactions or a reentrancy guard, or add an alternative withdrawal path / configurable gas stipend.","evidence":"Bytecode shows `PUSH2 0x08fc` (2300) immediately before low-level CALLs that transfer value; CALL opcodes at pc 0x3dd and 0x8af.","locations":["pc:0x3dd","pc:0x8af","pc:0x3ae","pc:0x897"]}]}
tokens used
99,309
{
"codex": {
"ran_at": "2026-01-13T02:38:32.846096+00:00",
"returncode": 0
},
"project": {
"mode": "bytecode",
"bytecode_length": 4792,
"bytecode_truncated": false,
"capability_graph_present": true,
"analysis_artifact_present": true
},
"summary": "Detected fixed-stipend ETH transfers via low-level CALLs; this pattern can brick withdrawals for contract recipients or after gas schedule changes.",
"raw_final": {
"summary": "Detected fixed-stipend ETH transfers via low-level CALLs; this pattern can brick withdrawals for contract recipients or after gas schedule changes.",
"findings": [
{
"title": "Fixed 2300-gas ETH transfers can make withdrawals revert for contract recipients",
"category": "other",
"evidence": "Bytecode shows `PUSH2 0x08fc` (2300) immediately before low-level CALLs that transfer value; CALL opcodes at pc 0x3dd and 0x8af.",
"severity": "low",
"locations": [
"pc:0x3dd",
"pc:0x8af",
"pc:0x3ae",
"pc:0x897"
],
"recommendation": "Use `call{value: amount}(\"\")` with full gas forwarding and protect with checks-effects-interactions or a reentrancy guard, or add an alternative withdrawal path / configurable gas stipend.",
"exploit_scenario": "If the beneficiary/owner address is a contract with a receive/fallback that needs more than the 2300 gas stipend (or gas costs increase), the CALL will fail and revert the withdrawal, potentially leaving ETH locked. This is inferred from bytecode and could be a false positive if an alternate withdrawal path exists."
}
],
"no_findings": false
},
"no_findings": false,
"schema_version": 1
}
00000000: PUSH1 0x60 00000002: PUSH1 0x40 00000004: MSTORE 00000005: PUSH1 0x04 00000007: CALLDATASIZE 00000008: LT 00000009: PUSH2 0x0099 0000000c: JUMPI 0000000d: PUSH1 0x00 0000000f: CALLDATALOAD 00000010: PUSH29 0x0100000000000000000000000000000000000000000000000000000000 0000002e: SWAP1 0000002f: DIV 00000030: PUSH4 0xffffffff 00000035: AND 00000036: DUP1 00000037: PUSH4 0x43d726d6 0000003c: EQ 0000003d: PUSH2 0x009e 00000040: JUMPI 00000041: DUP1 00000042: PUSH4 0x521eb273 00000047: EQ 00000048: PUSH2 0x00b3 0000004b: JUMPI 0000004c: DUP1 0000004d: PUSH4 0x8c52dc41 00000052: EQ 00000053: PUSH2 0x0108 00000056: JUMPI 00000057: DUP1 00000058: PUSH4 0x8da5cb5b 0000005d: EQ 0000005e: PUSH2 0x011d 00000061: JUMPI 00000062: DUP1 00000063: PUSH4 0xc19d93fb 00000068: EQ 00000069: PUSH2 0x0172 0000006c: JUMPI 0000006d: DUP1 0000006e: PUSH4 0xcb13cddb 00000073: EQ 00000074: PUSH2 0x01a9 00000077: JUMPI 00000078: DUP1 00000079: PUSH4 0xf2fde38b 0000007e: EQ 0000007f: PUSH2 0x01f6 00000082: JUMPI 00000083: DUP1 00000084: PUSH4 0xf340fa01 00000089: EQ 0000008a: PUSH2 0x022f 0000008d: JUMPI 0000008e: DUP1 0000008f: PUSH4 0xfa89401a 00000094: EQ 00000095: PUSH2 0x025d 00000098: JUMPI 00000099: JUMPDEST 0000009a: PUSH1 0x00 0000009c: DUP1 0000009d: REVERT 0000009e: JUMPDEST 0000009f: CALLVALUE 000000a0: ISZERO 000000a1: PUSH2 0x00a9 000000a4: JUMPI 000000a5: PUSH1 0x00 000000a7: DUP1 000000a8: REVERT 000000a9: JUMPDEST 000000aa: PUSH2 0x00b1 000000ad: PUSH2 0x0296 000000b0: JUMP 000000b1: JUMPDEST 000000b2: STOP 000000b3: JUMPDEST 000000b4: CALLVALUE 000000b5: ISZERO 000000b6: PUSH2 0x00be 000000b9: JUMPI 000000ba: PUSH1 0x00 000000bc: DUP1 000000bd: REVERT 000000be: JUMPDEST 000000bf: PUSH2 0x00c6 000000c2: PUSH2 0x03ef 000000c5: JUMP 000000c6: JUMPDEST 000000c7: PUSH1 0x40 000000c9: MLOAD 000000ca: DUP1 000000cb: DUP3 000000cc: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000000e1: AND 000000e2: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000000f7: AND 000000f8: DUP2 000000f9: MSTORE 000000fa: PUSH1 0x20 000000fc: ADD 000000fd: SWAP2 000000fe: POP 000000ff: POP 00000100: PUSH1 0x40 00000102: MLOAD 00000103: DUP1 00000104: SWAP2 00000105: SUB 00000106: SWAP1 00000107: RETURN 00000108: JUMPDEST 00000109: CALLVALUE 0000010a: ISZERO 0000010b: PUSH2 0x0113 0000010e: JUMPI 0000010f: PUSH1 0x00 00000111: DUP1 00000112: REVERT 00000113: JUMPDEST 00000114: PUSH2 0x011b 00000117: PUSH2 0x0415 0000011a: JUMP 0000011b: JUMPDEST 0000011c: STOP 0000011d: JUMPDEST 0000011e: CALLVALUE 0000011f: ISZERO 00000120: PUSH2 0x0128 00000123: JUMPI 00000124: PUSH1 0x00 00000126: DUP1 00000127: REVERT 00000128: JUMPDEST 00000129: PUSH2 0x0130 0000012c: PUSH2 0x04f6 0000012f: JUMP 00000130: JUMPDEST 00000131: PUSH1 0x40 00000133: MLOAD 00000134: DUP1 00000135: DUP3 00000136: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000014b: AND 0000014c: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000161: AND 00000162: DUP2 00000163: MSTORE 00000164: PUSH1 0x20 00000166: ADD 00000167: SWAP2 00000168: POP 00000169: POP 0000016a: PUSH1 0x40 0000016c: MLOAD 0000016d: DUP1 0000016e: SWAP2 0000016f: SUB 00000170: SWAP1 00000171: RETURN 00000172: JUMPDEST 00000173: CALLVALUE 00000174: ISZERO 00000175: PUSH2 0x017d 00000178: JUMPI 00000179: PUSH1 0x00 0000017b: DUP1 0000017c: REVERT 0000017d: JUMPDEST 0000017e: PUSH2 0x0185 00000181: PUSH2 0x051b 00000184: JUMP 00000185: JUMPDEST 00000186: PUSH1 0x40 00000188: MLOAD 00000189: DUP1 0000018a: DUP3 0000018b: PUSH1 0x02 0000018d: DUP2 0000018e: GT 0000018f: ISZERO 00000190: PUSH2 0x0195 00000193: JUMPI 00000194: INVALID 00000195: JUMPDEST 00000196: PUSH1 0xff 00000198: AND 00000199: DUP2 0000019a: MSTORE 0000019b: PUSH1 0x20 0000019d: ADD 0000019e: SWAP2 0000019f: POP 000001a0: POP 000001a1: PUSH1 0x40 000001a3: MLOAD 000001a4: DUP1 000001a5: SWAP2 000001a6: SUB 000001a7: SWAP1 000001a8: RETURN 000001a9: JUMPDEST 000001aa: CALLVALUE 000001ab: ISZERO 000001ac: PUSH2 0x01b4 000001af: JUMPI 000001b0: PUSH1 0x00 000001b2: DUP1 000001b3: REVERT 000001b4: JUMPDEST 000001b5: PUSH2 0x01e0 000001b8: PUSH1 0x04 000001ba: DUP1 000001bb: DUP1 000001bc: CALLDATALOAD 000001bd: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000001d2: AND 000001d3: SWAP1 000001d4: PUSH1 0x20 000001d6: ADD 000001d7: SWAP1 000001d8: SWAP2 000001d9: SWAP1 000001da: POP 000001db: POP 000001dc: PUSH2 0x052e 000001df: JUMP 000001e0: JUMPDEST 000001e1: PUSH1 0x40 000001e3: MLOAD 000001e4: DUP1 000001e5: DUP3 000001e6: DUP2 000001e7: MSTORE 000001e8: PUSH1 0x20 000001ea: ADD 000001eb: SWAP2 000001ec: POP 000001ed: POP 000001ee: PUSH1 0x40 000001f0: MLOAD 000001f1: DUP1 000001f2: SWAP2 000001f3: SUB 000001f4: SWAP1 000001f5: RETURN 000001f6: JUMPDEST 000001f7: CALLVALUE 000001f8: ISZERO 000001f9: PUSH2 0x0201 000001fc: JUMPI 000001fd: PUSH1 0x00 000001ff: DUP1 00000200: REVERT 00000201: JUMPDEST 00000202: PUSH2 0x022d 00000205: PUSH1 0x04 00000207: DUP1 00000208: DUP1 00000209: CALLDATALOAD 0000020a: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000021f: AND 00000220: SWAP1 00000221: PUSH1 0x20 00000223: ADD 00000224: SWAP1 00000225: SWAP2 00000226: SWAP1 00000227: POP 00000228: POP 00000229: PUSH2 0x0546 0000022c: JUMP 0000022d: JUMPDEST 0000022e: STOP 0000022f: JUMPDEST 00000230: PUSH2 0x025b 00000233: PUSH1 0x04 00000235: DUP1 00000236: DUP1 00000237: CALLDATALOAD 00000238: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000024d: AND 0000024e: SWAP1 0000024f: PUSH1 0x20 00000251: ADD 00000252: SWAP1 00000253: SWAP2 00000254: SWAP1 00000255: POP 00000256: POP 00000257: PUSH2 0x069b 0000025a: JUMP 0000025b: JUMPDEST 0000025c: STOP 0000025d: JUMPDEST 0000025e: CALLVALUE 0000025f: ISZERO 00000260: PUSH2 0x0268 00000263: JUMPI 00000264: PUSH1 0x00 00000266: DUP1 00000267: REVERT 00000268: JUMPDEST 00000269: PUSH2 0x0294 0000026c: PUSH1 0x04 0000026e: DUP1 0000026f: DUP1 00000270: CALLDATALOAD 00000271: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000286: AND 00000287: SWAP1 00000288: PUSH1 0x20 0000028a: ADD 0000028b: SWAP1 0000028c: SWAP2 0000028d: SWAP1 0000028e: POP 0000028f: POP 00000290: PUSH2 0x07c2 00000293: JUMP 00000294: JUMPDEST 00000295: STOP 00000296: JUMPDEST 00000297: PUSH1 0x00 00000299: DUP1 0000029a: SWAP1 0000029b: SLOAD 0000029c: SWAP1 0000029d: PUSH2 0x0100 000002a0: EXP 000002a1: SWAP1 000002a2: DIV 000002a3: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000002b8: AND 000002b9: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000002ce: AND 000002cf: CALLER 000002d0: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000002e5: AND 000002e6: EQ 000002e7: ISZERO 000002e8: ISZERO 000002e9: PUSH2 0x02f1 000002ec: JUMPI 000002ed: PUSH1 0x00 000002ef: DUP1 000002f0: REVERT 000002f1: JUMPDEST 000002f2: PUSH1 0x00 000002f4: PUSH1 0x02 000002f6: DUP2 000002f7: GT 000002f8: ISZERO 000002f9: PUSH2 0x02fe 000002fc: JUMPI 000002fd: INVALID 000002fe: JUMPDEST 000002ff: PUSH1 0x02 00000301: PUSH1 0x14 00000303: SWAP1 00000304: SLOAD 00000305: SWAP1 00000306: PUSH2 0x0100 00000309: EXP 0000030a: SWAP1 0000030b: DIV 0000030c: PUSH1 0xff 0000030e: AND 0000030f: PUSH1 0x02 00000311: DUP2 00000312: GT 00000313: ISZERO 00000314: PUSH2 0x0319 00000317: JUMPI 00000318: INVALID 00000319: JUMPDEST 0000031a: EQ 0000031b: ISZERO 0000031c: ISZERO 0000031d: PUSH2 0x0325 00000320: JUMPI 00000321: PUSH1 0x00 00000323: DUP1 00000324: REVERT 00000325: JUMPDEST 00000326: PUSH1 0x02 00000328: DUP1 00000329: PUSH1 0x14 0000032b: PUSH2 0x0100 0000032e: EXP 0000032f: DUP2 00000330: SLOAD 00000331: DUP2 00000332: PUSH1 0xff 00000334: MUL 00000335: NOT 00000336: AND 00000337: SWAP1 00000338: DUP4 00000339: PUSH1 0x02 0000033b: DUP2 0000033c: GT 0000033d: ISZERO 0000033e: PUSH2 0x0343 00000341: JUMPI 00000342: INVALID 00000343: JUMPDEST 00000344: MUL 00000345: OR 00000346: SWAP1 00000347: SSTORE 00000348: POP 00000349: PUSH32 0x1cdde67b72a90f19919ac732a437ac2f7a10fc128d28c2a6e525d89ce5cd9d3a 0000036a: PUSH1 0x40 0000036c: MLOAD 0000036d: PUSH1 0x40 0000036f: MLOAD 00000370: DUP1 00000371: SWAP2 00000372: SUB 00000373: SWAP1 00000374: LOG1 00000375: PUSH1 0x02 00000377: PUSH1 0x00 00000379: SWAP1 0000037a: SLOAD 0000037b: SWAP1 0000037c: PUSH2 0x0100 0000037f: EXP 00000380: SWAP1 00000381: DIV 00000382: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000397: AND 00000398: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000003ad: AND 000003ae: PUSH2 0x08fc 000003b1: ADDRESS 000003b2: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000003c7: AND 000003c8: BALANCE 000003c9: SWAP1 000003ca: DUP2 000003cb: ISZERO 000003cc: MUL 000003cd: SWAP1 000003ce: PUSH1 0x40 000003d0: MLOAD 000003d1: PUSH1 0x00 000003d3: PUSH1 0x40 000003d5: MLOAD 000003d6: DUP1 000003d7: DUP4 000003d8: SUB 000003d9: DUP2 000003da: DUP6 000003db: DUP9 000003dc: DUP9 000003dd: CALL 000003de: SWAP4 000003df: POP 000003e0: POP 000003e1: POP 000003e2: POP 000003e3: ISZERO 000003e4: ISZERO 000003e5: PUSH2 0x03ed 000003e8: JUMPI 000003e9: PUSH1 0x00 000003eb: DUP1 000003ec: REVERT 000003ed: JUMPDEST 000003ee: JUMP 000003ef: JUMPDEST 000003f0: PUSH1 0x02 000003f2: PUSH1 0x00 000003f4: SWAP1 000003f5: SLOAD 000003f6: SWAP1 000003f7: PUSH2 0x0100 000003fa: EXP 000003fb: SWAP1 000003fc: DIV 000003fd: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000412: AND 00000413: DUP2 00000414: JUMP 00000415: JUMPDEST 00000416: PUSH1 0x00 00000418: DUP1 00000419: SWAP1 0000041a: SLOAD 0000041b: SWAP1 0000041c: PUSH2 0x0100 0000041f: EXP 00000420: SWAP1 00000421: DIV 00000422: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000437: AND 00000438: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000044d: AND 0000044e: CALLER 0000044f: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000464: AND 00000465: EQ 00000466: ISZERO 00000467: ISZERO 00000468: PUSH2 0x0470 0000046b: JUMPI 0000046c: PUSH1 0x00 0000046e: DUP1 0000046f: REVERT 00000470: JUMPDEST 00000471: PUSH1 0x00 00000473: PUSH1 0x02 00000475: DUP2 00000476: GT 00000477: ISZERO 00000478: PUSH2 0x047d 0000047b: JUMPI 0000047c: INVALID 0000047d: JUMPDEST 0000047e: PUSH1 0x02 00000480: PUSH1 0x14 00000482: SWAP1 00000483: SLOAD 00000484: SWAP1 00000485: PUSH2 0x0100 00000488: EXP 00000489: SWAP1 0000048a: DIV 0000048b: PUSH1 0xff 0000048d: AND 0000048e: PUSH1 0x02 00000490: DUP2 00000491: GT 00000492: ISZERO 00000493: PUSH2 0x0498 00000496: JUMPI 00000497: INVALID 00000498: JUMPDEST 00000499: EQ 0000049a: ISZERO 0000049b: ISZERO 0000049c: PUSH2 0x04a4 0000049f: JUMPI 000004a0: PUSH1 0x00 000004a2: DUP1 000004a3: REVERT 000004a4: JUMPDEST 000004a5: PUSH1 0x01 000004a7: PUSH1 0x02 000004a9: PUSH1 0x14 000004ab: PUSH2 0x0100 000004ae: EXP 000004af: DUP2 000004b0: SLOAD 000004b1: DUP2 000004b2: PUSH1 0xff 000004b4: MUL 000004b5: NOT 000004b6: AND 000004b7: SWAP1 000004b8: DUP4 000004b9: PUSH1 0x02 000004bb: DUP2 000004bc: GT 000004bd: ISZERO 000004be: PUSH2 0x04c3 000004c1: JUMPI 000004c2: INVALID 000004c3: JUMPDEST 000004c4: MUL 000004c5: OR 000004c6: SWAP1 000004c7: SSTORE 000004c8: POP 000004c9: PUSH32 0x599d8e5a83cffb867d051598c4d70e805d59802d8081c1c7d6dffc5b6aca2b89 000004ea: PUSH1 0x40 000004ec: MLOAD 000004ed: PUSH1 0x40 000004ef: MLOAD 000004f0: DUP1 000004f1: SWAP2 000004f2: SUB 000004f3: SWAP1 000004f4: LOG1 000004f5: JUMP 000004f6: JUMPDEST 000004f7: PUSH1 0x00 000004f9: DUP1 000004fa: SWAP1 000004fb: SLOAD 000004fc: SWAP1 000004fd: PUSH2 0x0100 00000500: EXP 00000501: SWAP1 00000502: DIV 00000503: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000518: AND 00000519: DUP2 0000051a: JUMP 0000051b: JUMPDEST 0000051c: PUSH1 0x02 0000051e: PUSH1 0x14 00000520: SWAP1 00000521: SLOAD 00000522: SWAP1 00000523: PUSH2 0x0100 00000526: EXP 00000527: SWAP1 00000528: DIV 00000529: PUSH1 0xff 0000052b: AND 0000052c: DUP2 0000052d: JUMP 0000052e: JUMPDEST 0000052f: PUSH1 0x01 00000531: PUSH1 0x20 00000533: MSTORE 00000534: DUP1 00000535: PUSH1 0x00 00000537: MSTORE 00000538: PUSH1 0x40 0000053a: PUSH1 0x00 0000053c: KECCAK256 0000053d: PUSH1 0x00 0000053f: SWAP2 00000540: POP 00000541: SWAP1 00000542: POP 00000543: SLOAD 00000544: DUP2 00000545: JUMP 00000546: JUMPDEST 00000547: PUSH1 0x00 00000549: DUP1 0000054a: SWAP1 0000054b: SLOAD 0000054c: SWAP1 0000054d: PUSH2 0x0100 00000550: EXP 00000551: SWAP1 00000552: DIV 00000553: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000568: AND 00000569: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000057e: AND 0000057f: CALLER 00000580: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000595: AND 00000596: EQ 00000597: ISZERO 00000598: ISZERO 00000599: PUSH2 0x05a1 0000059c: JUMPI 0000059d: PUSH1 0x00 0000059f: DUP1 000005a0: REVERT 000005a1: JUMPDEST 000005a2: PUSH1 0x00 000005a4: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000005b9: AND 000005ba: DUP2 000005bb: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000005d0: AND 000005d1: EQ 000005d2: ISZERO 000005d3: ISZERO 000005d4: ISZERO 000005d5: PUSH2 0x05dd 000005d8: JUMPI 000005d9: PUSH1 0x00 000005db: DUP1 000005dc: REVERT 000005dd: JUMPDEST 000005de: DUP1 000005df: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000005f4: AND 000005f5: PUSH1 0x00 000005f7: DUP1 000005f8: SWAP1 000005f9: SLOAD 000005fa: SWAP1 000005fb: PUSH2 0x0100 000005fe: EXP 000005ff: SWAP1 00000600: DIV 00000601: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000616: AND 00000617: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000062c: AND 0000062d: PUSH32 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 0000064e: PUSH1 0x40 00000650: MLOAD 00000651: PUSH1 0x40 00000653: MLOAD 00000654: DUP1 00000655: SWAP2 00000656: SUB 00000657: SWAP1 00000658: LOG3 00000659: DUP1 0000065a: PUSH1 0x00 0000065c: DUP1 0000065d: PUSH2 0x0100 00000660: EXP 00000661: DUP2 00000662: SLOAD 00000663: DUP2 00000664: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000679: MUL 0000067a: NOT 0000067b: AND 0000067c: SWAP1 0000067d: DUP4 0000067e: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000693: AND 00000694: MUL 00000695: OR 00000696: SWAP1 00000697: SSTORE 00000698: POP 00000699: POP 0000069a: JUMP 0000069b: JUMPDEST 0000069c: PUSH1 0x00 0000069e: DUP1 0000069f: SWAP1 000006a0: SLOAD 000006a1: SWAP1 000006a2: PUSH2 0x0100 000006a5: EXP 000006a6: SWAP1 000006a7: DIV 000006a8: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000006bd: AND 000006be: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000006d3: AND 000006d4: CALLER 000006d5: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000006ea: AND 000006eb: EQ 000006ec: ISZERO 000006ed: ISZERO 000006ee: PUSH2 0x06f6 000006f1: JUMPI 000006f2: PUSH1 0x00 000006f4: DUP1 000006f5: REVERT 000006f6: JUMPDEST 000006f7: PUSH1 0x00 000006f9: PUSH1 0x02 000006fb: DUP2 000006fc: GT 000006fd: ISZERO 000006fe: PUSH2 0x0703 00000701: JUMPI 00000702: INVALID 00000703: JUMPDEST 00000704: PUSH1 0x02 00000706: PUSH1 0x14 00000708: SWAP1 00000709: SLOAD 0000070a: SWAP1 0000070b: PUSH2 0x0100 0000070e: EXP 0000070f: SWAP1 00000710: DIV 00000711: PUSH1 0xff 00000713: AND 00000714: PUSH1 0x02 00000716: DUP2 00000717: GT 00000718: ISZERO 00000719: PUSH2 0x071e 0000071c: JUMPI 0000071d: INVALID 0000071e: JUMPDEST 0000071f: EQ 00000720: ISZERO 00000721: ISZERO 00000722: PUSH2 0x072a 00000725: JUMPI 00000726: PUSH1 0x00 00000728: DUP1 00000729: REVERT 0000072a: JUMPDEST 0000072b: PUSH2 0x077c 0000072e: CALLVALUE 0000072f: PUSH1 0x01 00000731: PUSH1 0x00 00000733: DUP5 00000734: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000749: AND 0000074a: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000075f: AND 00000760: DUP2 00000761: MSTORE 00000762: PUSH1 0x20 00000764: ADD 00000765: SWAP1 00000766: DUP2 00000767: MSTORE 00000768: PUSH1 0x20 0000076a: ADD 0000076b: PUSH1 0x00 0000076d: KECCAK256 0000076e: SLOAD 0000076f: PUSH2 0x0911 00000772: SWAP1 00000773: SWAP2 00000774: SWAP1 00000775: PUSH4 0xffffffff 0000077a: AND 0000077b: JUMP 0000077c: JUMPDEST 0000077d: PUSH1 0x01 0000077f: PUSH1 0x00 00000781: DUP4 00000782: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000797: AND 00000798: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000007ad: AND 000007ae: DUP2 000007af: MSTORE 000007b0: PUSH1 0x20 000007b2: ADD 000007b3: SWAP1 000007b4: DUP2 000007b5: MSTORE 000007b6: PUSH1 0x20 000007b8: ADD 000007b9: PUSH1 0x00 000007bb: KECCAK256 000007bc: DUP2 000007bd: SWAP1 000007be: SSTORE 000007bf: POP 000007c0: POP 000007c1: JUMP 000007c2: JUMPDEST 000007c3: PUSH1 0x00 000007c5: PUSH1 0x01 000007c7: PUSH1 0x02 000007c9: DUP2 000007ca: GT 000007cb: ISZERO 000007cc: PUSH2 0x07d1 000007cf: JUMPI 000007d0: INVALID 000007d1: JUMPDEST 000007d2: PUSH1 0x02 000007d4: PUSH1 0x14 000007d6: SWAP1 000007d7: SLOAD 000007d8: SWAP1 000007d9: PUSH2 0x0100 000007dc: EXP 000007dd: SWAP1 000007de: DIV 000007df: PUSH1 0xff 000007e1: AND 000007e2: PUSH1 0x02 000007e4: DUP2 000007e5: GT 000007e6: ISZERO 000007e7: PUSH2 0x07ec 000007ea: JUMPI 000007eb: INVALID 000007ec: JUMPDEST 000007ed: EQ 000007ee: ISZERO 000007ef: ISZERO 000007f0: PUSH2 0x07f8 000007f3: JUMPI 000007f4: PUSH1 0x00 000007f6: DUP1 000007f7: REVERT 000007f8: JUMPDEST 000007f9: PUSH1 0x01 000007fb: PUSH1 0x00 000007fd: DUP4 000007fe: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000813: AND 00000814: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000829: AND 0000082a: DUP2 0000082b: MSTORE 0000082c: PUSH1 0x20 0000082e: ADD 0000082f: SWAP1 00000830: DUP2 00000831: MSTORE 00000832: PUSH1 0x20 00000834: ADD 00000835: PUSH1 0x00 00000837: KECCAK256 00000838: SLOAD 00000839: SWAP1 0000083a: POP 0000083b: PUSH1 0x00 0000083d: PUSH1 0x01 0000083f: PUSH1 0x00 00000841: DUP5 00000842: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000857: AND 00000858: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 0000086d: AND 0000086e: DUP2 0000086f: MSTORE 00000870: PUSH1 0x20 00000872: ADD 00000873: SWAP1 00000874: DUP2 00000875: MSTORE 00000876: PUSH1 0x20 00000878: ADD 00000879: PUSH1 0x00 0000087b: KECCAK256 0000087c: DUP2 0000087d: SWAP1 0000087e: SSTORE 0000087f: POP 00000880: DUP2 00000881: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 00000896: AND 00000897: PUSH2 0x08fc 0000089a: DUP3 0000089b: SWAP1 0000089c: DUP2 0000089d: ISZERO 0000089e: MUL 0000089f: SWAP1 000008a0: PUSH1 0x40 000008a2: MLOAD 000008a3: PUSH1 0x00 000008a5: PUSH1 0x40 000008a7: MLOAD 000008a8: DUP1 000008a9: DUP4 000008aa: SUB 000008ab: DUP2 000008ac: DUP6 000008ad: DUP9 000008ae: DUP9 000008af: CALL 000008b0: SWAP4 000008b1: POP 000008b2: POP 000008b3: POP 000008b4: POP 000008b5: ISZERO 000008b6: ISZERO 000008b7: PUSH2 0x08bf 000008ba: JUMPI 000008bb: PUSH1 0x00 000008bd: DUP1 000008be: REVERT 000008bf: JUMPDEST 000008c0: DUP2 000008c1: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000008d6: AND 000008d7: PUSH32 0xd7dee2702d63ad89917b6a4da9981c90c4d24f8c2bdfd64c604ecae57d8d0651 000008f8: DUP3 000008f9: PUSH1 0x40 000008fb: MLOAD 000008fc: DUP1 000008fd: DUP3 000008fe: DUP2 000008ff: MSTORE 00000900: PUSH1 0x20 00000902: ADD 00000903: SWAP2 00000904: POP 00000905: POP 00000906: PUSH1 0x40 00000908: MLOAD 00000909: DUP1 0000090a: SWAP2 0000090b: SUB 0000090c: SWAP1 0000090d: LOG2 0000090e: POP 0000090f: POP 00000910: JUMP 00000911: JUMPDEST 00000912: PUSH1 0x00 00000914: DUP1 00000915: DUP3 00000916: DUP5 00000917: ADD 00000918: SWAP1 00000919: POP 0000091a: DUP4 0000091b: DUP2 0000091c: LT 0000091d: ISZERO 0000091e: ISZERO 0000091f: ISZERO 00000920: PUSH2 0x0925 00000923: JUMPI 00000924: INVALID 00000925: JUMPDEST 00000926: DUP1 00000927: SWAP2 00000928: POP 00000929: POP 0000092a: SWAP3 0000092b: SWAP2 0000092c: POP 0000092d: POP 0000092e: JUMP 0000092f: STOP 00000930: LOG1 00000931: PUSH6 0x627a7a723058 00000938: KECCAK256 00000939: SWAP4 0000093a: UNKNOWN(0x2A) 0000093b: RETURNDATACOPY 0000093c: MUL 0000093d: SWAP16 0000093e: UNKNOWN(0xC6) 0000093f: LT 00000940: UNKNOWN(0xE9) 00000941: MULMOD 00000942: DUP6 00000943: ADDRESS 00000944: SIGNEXTEND 00000945: CALLCODE 00000946: PUSH16 0x653d2ece3258ea9eb306c2b0831c4f6f 00000957: UNKNOWN(0xE7) 00000958: SWAP7 00000959: STOP 0000095a: UNKNOWN(0x29)
| Severity | Category | Tool | Title | Confidence | Validated | Confirmed | Details |
|---|---|---|---|---|---|---|---|
| medium | other | detector | Untrusted CALL target/value reachable | 45 | no | no |
viewtrace_id: 0xbe7fa21493096cb06f927dd3e6e7833dde89101c02664ed01f2e2b4edc01d401
call_targets:
0x91bf99ca34268d407f3cc8d6525ce83c6ea7bcf5
target_varies:
no
classification:
constant_target
validation_json{
"sink": "CALL",
"errors": 0,
"status": "sink_reached",
"attempts": 1,
"trace_id": "0xbe7fa21493096cb06f927dd3e6e7833dde89101c02664ed01f2e2b4edc01d401",
"confirmed": false,
"trace_mode": "callTracer",
"call_targets": [
"0x91bf99ca34268d407f3cc8d6525ce83c6ea7bcf5"
],
"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": "0xffffffff",
"selector": "0xffffffff",
"calldata_variants": [
"0xffffffff",
"0xffffffff0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x43d726d6",
"selector": "0x43d726d6",
"calldata_variants": [
"0x43d726d6",
"0x43d726d60000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x521eb273",
"selector": "0x521eb273",
"calldata_variants": [
"0x521eb273",
"0x521eb2730000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8c52dc41",
"selector": "0x8c52dc41",
"calldata_variants": [
"0x8c52dc41",
"0x8c52dc410000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8da5cb5b",
"selector": "0x8da5cb5b",
"calldata_variants": [
"0x8da5cb5b",
"0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xc19d93fb",
"selector": "0xc19d93fb",
"calldata_variants": [
"0xc19d93fb",
"0xc19d93fb0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xcb13cddb",
"selector": "0xcb13cddb",
"calldata_variants": [
"0xcb13cddb",
"0xcb13cddb0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf2fde38b",
"selector": "0xf2fde38b",
"calldata_variants": [
"0xf2fde38b",
"0xf2fde38b0000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 989,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "constant",
"target_expression_category": "computed"
},
{
"pc": 2223,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
},
{
"pc": 2373,
"opcode": "CALLCODE",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
}
],
"call_count": 3,
"guards_detected": [
{
"pc": 719,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
},
{
"pc": 1102,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
},
{
"pc": 1407,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
},
{
"pc": 1748,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
}
],
"untrusted_call_count": 3
}
|
| medium | other | detector | ETH value transfer possible | 40 | no | no |
viewtrace_id: 0xbe7fa21493096cb06f927dd3e6e7833dde89101c02664ed01f2e2b4edc01d401
call_targets:
0x91bf99ca34268d407f3cc8d6525ce83c6ea7bcf5
target_varies:
no
classification:
constant_target
validation_json{
"sink": "CALL",
"errors": 0,
"status": "sink_reached",
"attempts": 1,
"trace_id": "0xbe7fa21493096cb06f927dd3e6e7833dde89101c02664ed01f2e2b4edc01d401",
"confirmed": false,
"trace_mode": "callTracer",
"call_targets": [
"0x91bf99ca34268d407f3cc8d6525ce83c6ea7bcf5"
],
"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": "0xffffffff",
"selector": "0xffffffff",
"calldata_variants": [
"0xffffffff",
"0xffffffff0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x43d726d6",
"selector": "0x43d726d6",
"calldata_variants": [
"0x43d726d6",
"0x43d726d60000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x521eb273",
"selector": "0x521eb273",
"calldata_variants": [
"0x521eb273",
"0x521eb2730000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8c52dc41",
"selector": "0x8c52dc41",
"calldata_variants": [
"0x8c52dc41",
"0x8c52dc410000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8da5cb5b",
"selector": "0x8da5cb5b",
"calldata_variants": [
"0x8da5cb5b",
"0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xc19d93fb",
"selector": "0xc19d93fb",
"calldata_variants": [
"0xc19d93fb",
"0xc19d93fb0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xcb13cddb",
"selector": "0xcb13cddb",
"calldata_variants": [
"0xcb13cddb",
"0xcb13cddb0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf2fde38b",
"selector": "0xf2fde38b",
"calldata_variants": [
"0xf2fde38b",
"0xf2fde38b0000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 989,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "constant",
"target_expression_category": "computed"
},
{
"pc": 2223,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
},
{
"pc": 2373,
"opcode": "CALLCODE",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
}
],
"eth_value_calls": 3,
"guards_detected": [
{
"pc": 719,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
},
{
"pc": 1102,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
},
{
"pc": 1407,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
},
{
"pc": 1748,
"type": "msg_sender_eq_const",
"value": "0xffffffffffffffffffffffffffffffffffffffff"
}
]
}
|
| low | other | codex | Fixed 2300-gas ETH transfers can make withdrawals revert for contract recipients | 65 | no | — |
viewevidence_json{
"evidence": "Bytecode shows `PUSH2 0x08fc` (2300) immediately before low-level CALLs that transfer value; CALL opcodes at pc 0x3dd and 0x8af.",
"locations": [
"pc:0x3dd",
"pc:0x8af",
"pc:0x3ae",
"pc:0x897"
],
"recommendation": "Use `call{value: amount}(\"\")` with full gas forwarding and protect with checks-effects-interactions or a reentrancy guard, or add an alternative withdrawal path / configurable gas stipend.",
"exploit_scenario": "If the beneficiary/owner address is a contract with a receive/fallback that needs more than the 2300 gas stipend (or gas costs increase), the CALL will fail and revert the withdrawal, potentially leaving ETH locked. This is inferred from bytecode and could be a false positive if an alternate withdrawal path exists."
}
|