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

Analysis Run

019bab3b-aba8-711d-8ff4-ada11975c85e

complete
Chain ID
1
Address
Block Number
Created
Sun, Jan 11, 2026 4:06 AM
Review Summary

What survived the funnel

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

Confirmed
0
Validated
0
Source
Bytecode only
Review Backing
Present
Best current signal
Potentially unguarded arbitrary CALL with ETH value (reachability unclear)
crit 0 high 0 direct contract
Review Checklist
1. Read the findings table first. Ignore raw jobs until the result looks real.
2. Confirm attacker control, not just the existence of a sink.
3. Confirm money or privilege impact.
4. Keep it if the behavior is real. Kill it if this is normal proxy, admin, or upgrade plumbing.

Processing Jobs

Status & attempts
ID Type Status Attempts Heartbeat
38604 artifact.fetch complete 1 / 3 3 months ago
38605 proxy.resolve complete 1 / 3 3 months ago
38606 tool.cast_disasm complete 1 / 3 3 months ago
38607 analysis.bundle complete 1 / 3 3 months ago
38608 capability.graph complete 1 / 3 3 months ago
38609 detector.run complete 1 / 3 3 months ago
38610 validation.fork complete 1 / 3 3 months ago
39087 report.consolidate complete 1 / 6 3 months ago

Artifact

Runtime bytecode: available
Creation TX:
Deployer:
Proxy: no not_proxy
Implementation:
Verified Source: no
Proxy evidence
{
    "status": "not_proxy"
}

Slither

tool.slither

No slither job recorded yet.

Codex

report.consolidate
Job Status
complete
Attempts
1 / 6
Findings
1
No findings?
no
Summary
Two low-level CALL sites exist with computed target/value; one appears owner/time-locked, while the reachability/guarding of the pc:0x44a CALL is unclear from the bytecode graph and could allow arbitrary external calls if exposed.
View stdout
{"no_findings":false,"summary":"Two low-level CALL sites exist with computed target/value; one appears owner/time-locked, while the reachability/guarding of the pc:0x44a CALL is unclear from the bytecode graph and could allow arbitrary external calls if exposed.","findings":[{"severity":"medium","category":"access_control","title":"Potentially unguarded arbitrary CALL with ETH value (reachability unclear)","exploit_scenario":"If the code path containing the CALL at pc:0x44a (1098) is reachable from a public selector and its target/value are derived from calldata or other user-controlled inputs, any caller could trigger arbitrary external calls (and potentially transfer ETH) from this contract. This could allow draining ETH, token approvals/transfers, or interaction with attacker-controlled contracts. However, the control-flow graph does not clearly link this block to the dispatcher, and one dynamic trace observed a constant target (self), so actual exploitability is uncertain.","recommendation":"Confirm whether the pc:0x44a call path is reachable from any external selector and whether its target/value are user-controlled. If reachable, add explicit access control (owner/time-lock/allowlist) and validate target/value. If the call is intended to be a self-call or a fixed target, hardcode it or add assertions to prevent user-controlled targets.","evidence":"Bytecode analysis shows CALL at pc 1098 with target/value classified as computed (`callsites`), and no CALLER-based guard appears in nearby blocks (pc 953/1004/1080). Detector flagged both \"Untrusted CALL target/value reachable\" and \"ETH value transfer possible\" for this callsite; validation trace observed a constant target (self), so control is uncertain.","locations":["pc:0x44a","pc:0x3b8","pc:0x3ec"]}]}
View stderr
OpenAI Codex v0.77.0 (research preview)
--------
workdir: /tmp/codex-86npeb2q
model: gpt-5.2-codex
provider: openai
approval: never
sandbox: read-only
reasoning effort: high
reasoning summaries: auto
session id: 019babb8-52c4-7d61-9b07-2f7c161f6450
--------
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-86npeb2q succeeded in 5ms:
BYTECODE_BUNDLE.json
codex-output-schema.json
exec
/bin/bash -lc 'cat BYTECODE_BUNDLE.json' in /tmp/codex-86npeb2q succeeded in 11ms:
{
  "analysis_artifact": {
    "address": "0x367ba7d034abf0b97bccdf07fd95217410c9dbe8",
    "artifact_hash": "0xc67fdf84eaee7efdf3e172f1d56ca90619532781164a797ad694bc528fdb2089",
    "artifact_json": {
      "auth": {
        "guards": [
          {
            "pc": 416,
            "type": "msg_sender_eq_const",
            "value": "0xffffffffffffffffffffffffffffffffffffffff"
          },
          {
            "pc": 786,
            "type": "msg_sender_eq_const",
            "value": "0xffffffffffffffffffffffffffffffffffffffff"
          }
        ]
      },
      "basic_blocks": [

thinking
**Investigating callsites and bytecode details**

I’m focusing on understanding the suspicious CALL instructions at pc 584 and 1098 by parsing the artifact’s opcode blocks, especially around pc 502–596. There’s complexity around how addresses and values like SELFBALANCE are computed, with guarding logic that might be degenerate or unreachable. The large JSON artifact might require using jq or Python to locate and analyze these callsites more precisely, since some parts seem truncated. I want to extract exact bytecode and control flow details to clarify the transfer and target behavior.
exec
/bin/bash -lc "python - <<'PY'
import json
import sys
from pathlib import Path
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# find blocks containing pc 1098 or callsite 1098
for b in blocks:
    if b.get('type')=='basic_block':
        start=b.get('start_pc')
        end=b.get('end_pc')
        if start is not None and end is not None and start<=1098<=end:
            print('block',start,end,'id',b.get('id'))
            print('opcodes',b.get('opcodes'))
            break
else:
    print('no block covering 1098')
# find block covering 584
for b in blocks:
    if b.get('type')=='basic_block':
        start=b.get('start_pc')
        end=b.get('end_pc')
        if start is not None and end is not None and start<=584<=end:
            print('block',start,end,'id',b.get('id'))
            print('opcodes',b.get('opcodes'))
            break
PY" in /tmp/codex-86npeb2q succeeded in 28ms:
no block covering 1098

thinking
**Investigating missing block around address 1098**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=[b for b in j['analysis_artifact']['artifact_json']['basic_blocks'] if b.get('type')=='basic_block']
for b in blocks:
    s,e=b.get('start_pc'),b.get('end_pc')
    if s is not None and e is not None and s>=1070 and s<=1120:
        print('block',s,e,'id',b.get('id'),'hash',b.get('hash'))
PY" in /tmp/codex-86npeb2q succeeded in 28ms:


thinking
**Investigating missing basic blocks**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
found=False
for b in blocks:
    if b.get('start_pc')==1104:
        print('found block',b)
        found=True
        break
print('count',len(blocks),'found',found)
PY" in /tmp/codex-86npeb2q succeeded in 76ms:
found block {'end_pc': 1114, 'hash': '0x8ebd94d87699ca2db03662333869d541106e8bbcebe87d832747cd139829d82e', 'opcodes': ['PUSH1', 'MLOAD', 'RETURNDATASIZE', 'PUSH1', 'OP_82', 'RETURNDATACOPY', 'RETURNDATASIZE', 'OP_81', 'REVERT'], 'start_pc': 1104}
count 127 found True

thinking
**Reevaluating block filtering criteria**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
for b in blocks:
    s,e=b.get('start_pc'),b.get('end_pc')
    if s is not None and e is not None and s<=1098<=e:
        print('block',s,e,'opcodes',b.get('opcodes'))
        break
else:
    print('no block covering 1098')

for b in blocks:
    s,e=b.get('start_pc'),b.get('end_pc')
    if s is not None and e is not None and s<=584<=e:
        print('block',s,e,'opcodes',b.get('opcodes'))
        break
PY" in /tmp/codex-86npeb2q succeeded in 35ms:
block 1080 1103 opcodes ['JUMPDEST', 'PUSH1', 'OP_80', 'PUSH1', 'PUSH1', 'OP_84', 'MLOAD', 'PUSH1', 'OP_86', 'ADD', 'PUSH1', 'OP_88', 'GAS', 'CALL', 'OP_80', 'PUSH2', 'JUMPI']
block 502 596 opcodes ['JUMPDEST', 'PUSH1', 'PUSH1', 'OP_90', 'SLOAD', 'OP_90', 'PUSH2', 'EXP', 'OP_90', 'DIV', 'PUSH20', 'AND', 'PUSH20', 'AND', 'PUSH2', 'SELFBALANCE', 'OP_90', 'OP_81', 'ISZERO', 'MUL', 'OP_90', 'PUSH1', 'MLOAD', 'PUSH1', 'PUSH1', 'MLOAD', 'OP_80', 'OP_83', 'SUB', 'OP_81', 'OP_85', 'OP_88', 'OP_88', 'CALL', 'OP_93', 'POP', 'POP', 'POP', 'POP', 'ISZERO', 'OP_80', 'ISZERO', 'PUSH2', 'JUMPI']

thinking
**Analyzing external calls and access controls**

I'm interpreting low-level CALL patterns to see if value (ETH) is transferred and if the call is untrusted. I'm spotting a common pattern where if amount==0, it sends the full balance using SELFBALANCE and ISZERO logic. I'm also checking for reentrancy guard absence and suspicious access control that requires msg.sender to be an unlikely reserved address. Function selectors hint at ownership and withdrawal features, and timestamp checks suggest time-lock behavior. No upgradeability detected, so I’m focusing on external call safety and storage control of addresses. Next, I'll dig into writing/storage instructions to verify if owners or addresses can be set or changed.
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
for b in blocks:
    ops=b.get('opcodes')
    if ops and 'SSTORE' in ops:
        print('block',b.get('start_pc'),b.get('end_pc'),ops)
PY" in /tmp/codex-86npeb2q succeeded in 26ms:


thinking
**Analyzing call targets and storage usage**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
for key in j['analysis_artifact']['artifact_json']:
    if 'storage' in key:
        print(key)
PY" in /tmp/codex-86npeb2q succeeded in 39ms:
storage
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
import pprint
pprint.pprint(j['analysis_artifact']['artifact_json']['storage'])
PY" in /tmp/codex-86npeb2q succeeded in 77ms:
{'keccak_count': 1,
 'reads': 9,
 'slots': [{'op': 'SLOAD',
            'pc': 286,
            'slot': '0x0000000000000000000000000000000000000000000000000000000000000000'},
           {'op': 'SLOAD',
            'pc': 292,
            'slot': '0x0000000000000000000000000000000000000000000000000000000000000000'},
           {'op': 'SLOAD',
            'pc': 364,
            'slot': '0x0000000000000000000000000000000000000000000000000000000000000000'},
           {'op': 'SLOAD',
            'pc': 508,
            'slot': '0x0000000000000000000000000000000000000000000000000000000000000000'},
           {'op': 'SLOAD',
            'pc': 613,
            'slot': '0x0000000000000000000000000000000000000000000000000000000000000000'},
           {'op': 'SLOAD',
            'pc': 627,
            'slot': '0x0000000000000000000000000000000000000000000000000000000000000000'},

thinking
**Analyzing immutable state and access control**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
print(j['analysis_artifact']['artifact_json'].keys())
PY" in /tmp/codex-86npeb2q succeeded in 26ms:
dict_keys(['auth', 'basic_blocks', 'callsites', 'cfg_edges', 'cfg_hash', 'dispatcher_type', 'function_entries', 'functions', 'selectors', 'sinks', 'storage', 'version'])

thinking
**Reviewing callsites list**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
print(j['analysis_artifact']['artifact_json']['callsites'])
PY" in /tmp/codex-86npeb2q succeeded in 44ms:
[{'opcode': 'CALL', 'pc': 584, 'returndata_checked': None, 'target_expression_category': 'computed', 'value_expression_category': 'computed'}, {'opcode': 'CALL', 'pc': 1098, 'returndata_checked': None, 'target_expression_category': 'computed', 'value_expression_category': 'computed'}]

thinking
**Examining callsites and selectors**
exec
/bin/bash -lc "python - <<'PY'
import json, pprint
j=json.load(open('BYTECODE_BUNDLE.json'))
pprint.pprint(j['analysis_artifact']['artifact_json']['selectors'])
PY" in /tmp/codex-86npeb2q succeeded in 57ms:
['0x251c1aa3', '0x3ccfd60b', '0x8380edb7', '0x8da5cb5b', '0xa1db9782']

thinking
**Inspecting function entries**
exec
/bin/bash -lc "python - <<'PY'
import json, pprint
j=json.load(open('BYTECODE_BUNDLE.json'))
pprint.pprint(j['analysis_artifact']['artifact_json']['function_entries'][:20])
PY" in /tmp/codex-86npeb2q succeeded in 57ms:
[{'entry_pc': 1020253707, 'selector': '0x251c1aa3'},
 {'entry_pc': 2206264759, 'selector': '0x3ccfd60b'},
 {'entry_pc': 2376452955, 'selector': '0x8380edb7'},
 {'entry_pc': 2715522946, 'selector': '0x8da5cb5b'},
 {'entry_pc': None, 'selector': '0xa1db9782'}]

thinking
**Assessing entry_pc and dispatcher_type values**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
print(j['analysis_artifact']['artifact_json']['dispatcher_type'])
PY" in /tmp/codex-86npeb2q succeeded in 32ms:
selector_jump_table

thinking
**Analyzing potential contract vulnerabilities**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
edges=j['analysis_artifact']['artifact_json']['cfg_edges']
# edges are tuples? let's inspect few
print('edges sample',edges[:10])
# find incoming edges to block start 1080
incoming=[e for e in edges if e[1]==1080]
print('incoming to 1080',incoming)
# find outgoing from 1080
outgoing=[e for e in edges if e[0]==1080]
print('outgoing from 1080',outgoing)
PY" in /tmp/codex-86npeb2q exited 1 in 29ms:
edges sample [{'from': 'bb:0', 'to': 'bb:78', 'type': 'control_flow'}, {'from': 'bb:0', 'to': 'bb:13', 'type': 'control_flow_fallthrough'}, {'from': 'bb:13', 'to': 'bb:90', 'type': 'control_flow'}, {'from': 'bb:13', 'to': 'bb:30', 'type': 'control_flow_fallthrough'}, {'from': 'bb:30', 'to': 'bb:133', 'type': 'control_flow'}, {'from': 'bb:30', 'to': 'bb:41', 'type': 'control_flow_fallthrough'}, {'from': 'bb:41', 'to': 'bb:156', 'type': 'control_flow'}, {'from': 'bb:41', 'to': 'bb:52', 'type': 'control_flow_fallthrough'}, {'from': 'bb:52', 'to': 'bb:199', 'type': 'control_flow'}, {'from': 'bb:52', 'to': 'bb:63', 'type': 'control_flow_fallthrough'}]
Traceback (most recent call last):
  File "<stdin>", line 7, in <module>
KeyError: 1

thinking
**Inspecting edge references and block IDs**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# build id map
id_map={}
for b in blocks:
    bid=b.get('id')
    if not bid:
        bid=f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
# find block id containing call pc 1098
call_pc=1098
call_block=None
for b in blocks:
    s,e=b.get('start_pc'),b.get('end_pc')
    if s is not None and e is not None and s<=call_pc<=e:
        call_block=b
        break
print('call block',call_block)
call_id=None
if call_block:
    call_id=call_block.get('id') or f\"bb:{call_block.get('start_pc')}\"
print('call_id',call_id)
# find incoming edges to call_id
edges=j['analysis_artifact']['artifact_json']['cfg_edges']
incoming=[e for e in edges if e['to']==call_id]
print('incoming count',len(incoming))
for e in incoming[:10]:
    b=id_map.get(e['from'])
    print('from',e['from'],'start',b.get('start_pc'),'end',b.get('end_pc'))
PY" in /tmp/codex-86npeb2q succeeded in 25ms:
call block {'end_pc': 1103, 'hash': '0xe3015edd169714b7335ceeb3f2c07515fe613b18f6f7c0c017556185b0cd9c76', 'opcodes': ['JUMPDEST', 'PUSH1', 'OP_80', 'PUSH1', 'PUSH1', 'OP_84', 'MLOAD', 'PUSH1', 'OP_86', 'ADD', 'PUSH1', 'OP_88', 'GAS', 'CALL', 'OP_80', 'PUSH2', 'JUMPI'], 'start_pc': 1080}
call_id bb:1080
incoming count 1
from bb:1004 start 1004 end 1074

thinking
**Inspecting opcodes for block 1004**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
for b in blocks:
    s=b.get('start_pc')
    if s==1004:
        print(b)
        break
PY" in /tmp/codex-86npeb2q succeeded in 27ms:
{'end_pc': 1074, 'hash': '0xfbf6db55d25b26744b8985113b4e865948bc0bb35e5a2ced2e23a937c5ab7d02', 'opcodes': ['JUMPDEST', 'PUSH1', 'MLOAD', 'PUSH1', 'OP_81', 'OP_83', 'SUB', 'SUB', 'OP_81', 'MSTORE', 'OP_90', 'PUSH1', 'MSTORE', 'OP_91', 'POP', 'PUSH1', 'SHL', 'PUSH1', 'OP_82', 'ADD', 'OP_80', 'MLOAD', 'PUSH28', 'OP_83', 'OP_81', 'OP_83', 'AND', 'OR', 'OP_83', 'MSTORE', 'POP', 'POP', 'POP', 'POP', 'PUSH2', 'JUMP'], 'start_pc': 1004}

thinking
**Inspecting calldata assembly**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# get id map
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
edges=j['analysis_artifact']['artifact_json']['cfg_edges']
# find incoming to bb:1004
incoming=[e for e in edges if e['to']=='bb:1004']
print('incoming to 1004',incoming)
for e in incoming:
    b=id_map.get(e['from'])
    print('from',e['from'],'start',b.get('start_pc'),'end',b.get('end_pc'),'ops',b.get('opcodes'))
PY" in /tmp/codex-86npeb2q succeeded in 25ms:
incoming to 1004 []

thinking
**Analyzing dispatcher-to-function edges**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# create map from bb id to start_pc
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
edges=j['analysis_artifact']['artifact_json']['cfg_edges']
# list edges from dispatcher blocks (start <=77 maybe)
for e in edges:
    fr=id_map.get(e['from'])
    to=id_map.get(e['to'])
    if fr and fr.get('start_pc') in (13,30,41,52,63,74):
        print('from',fr.get('start_pc'),'to',to.get('start_pc'), 'type',e['type'])
PY" in /tmp/codex-86npeb2q succeeded in 27ms:
from 13 to 90 type control_flow
from 13 to 30 type control_flow_fallthrough
from 30 to 133 type control_flow
from 30 to 41 type control_flow_fallthrough
from 41 to 156 type control_flow
from 41 to 52 type control_flow_fallthrough
from 52 to 199 type control_flow
from 52 to 63 type control_flow_fallthrough
from 63 to 242 type control_flow
from 63 to 74 type control_flow_fallthrough
from 74 to 85 type control_flow

thinking
**Tracing function entries and calls**
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict, deque
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id to block, id
def block_id(b):
    return b.get('id') or f\"bb:{b.get('start_pc')}\"

id_map={block_id(b):b for b in blocks}
# build adjacency
adj=defaultdict(list)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    adj[e['from']].append(e['to'])
# find block ids containing call pc
call_pcs=[584,1098]
call_blocks={}
for pc in call_pcs:
    for b in blocks:
        s,e=b.get('start_pc'),b.get('end_pc')
        if s is not None and e is not None and s<=pc<=e:
            call_blocks[pc]=block_id(b)
            break
print('call blocks',call_blocks)
# entry blocks from dispatcher
entry_starts=[90,133,156,199,242]
entry_ids=[f\"bb:{s}\" for s in entry_starts]
# BFS from each entry to see if reaches call blocks
for entry in entry_ids:
    for pc,cb in call_blocks.items():
        # BFS
        q=deque([entry]); seen=set([entry]); found=False
        while q and not found:
            cur=q.popleft()
            if cur==cb:
                found=True; break
            for nxt in adj.get(cur,[]):
                if nxt not in seen:
                    seen.add(nxt); q.append(nxt)
        if found:
            print('entry',entry,'reaches call pc',pc)
PY" in /tmp/codex-86npeb2q succeeded in 36ms:
call blocks {584: 'bb:502', 1098: 'bb:1080'}
entry bb:133 reaches call pc 584

thinking
**Analyzing unreachable call connections**
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
# build incoming counts
incoming=defaultdict(int)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    incoming[e['to']]+=1
# list blocks with no incoming
no_in=[bid for bid in id_map if incoming[bid]==0]
# show some with start_pc >= 200
for bid in sorted(no_in, key=lambda x: id_map[x].get('start_pc') or 0)[:20]:
    b=id_map[bid]
    print(bid,'start',b.get('start_pc'),'end',b.get('end_pc'))
print('total no incoming',len(no_in))
# show if bb:1004 or bb:1080 are no incoming
for bid in ['bb:1004','bb:1080']:
    print(bid,'incoming',incoming[bid])
PY" in /tmp/codex-86npeb2q succeeded in 25ms:
bb:0 start 0 end 12
bb:111 start 111 end 123
bb:124 start 124 end 132
bb:154 start 154 end 155
bb:177 start 177 end 189
bb:190 start 190 end 198
bb:220 start 220 end 232
bb:233 start 233 end 241
bb:276 start 276 end 280
bb:281 start 281 end 282
bb:349 start 349 end 357
bb:493 start 493 end 501
bb:719 start 719 end 727
bb:863 start 863 end 871
bb:949 start 949 end 952
bb:953 start 953 end 1003
bb:1004 start 1004 end 1074
bb:1075 start 1075 end 1079
bb:1227 start 1227 end 1235
bb:1261 start 1261 end 1266

thinking
**Analyzing subgraph with BFS**
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict, deque
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
adj=defaultdict(list)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    adj[e['from']].append(e['to'])
# find call block id
call_id=None
for b in blocks:
    s,e=b.get('start_pc'),b.get('end_pc')
    if s is not None and e is not None and s<=1098<=e:
        call_id=b.get('id') or f\"bb:{s}\"
        break
print('call block',call_id)
# try entries with no incoming near 900-1000
entries=[bid for bid,b in id_map.items() if b.get('start_pc') in (949,953,1004,1075)]
print('entries',entries)
for entry in entries:
    # BFS
    q=deque([entry]); seen=set([entry]); found=False
    while q and not found:
        cur=q.popleft()
        if cur==call_id:
            found=True; break
        for nxt in adj.get(cur,[]):
            if nxt not in seen:
                seen.add(nxt); q.append(nxt)
    print(entry,'reaches call',found)
PY" in /tmp/codex-86npeb2q succeeded in 59ms:
call block bb:1080
entries ['bb:949', 'bb:953', 'bb:1004', 'bb:1075']
bb:949 reaches call False
bb:953 reaches call False
bb:1004 reaches call True
bb:1075 reaches call False

thinking
**Analyzing function entry and computed jumps**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
for s in [872,949,953,1004,1075,1080,1104]:
    for b in blocks:
        if b.get('start_pc')==s:
            print('block',s,b.get('end_pc'))
            print(b.get('opcodes'))
            break
PY" in /tmp/codex-86npeb2q succeeded in 76ms:
block 872 948
['JUMPDEST', 'PUSH2', 'PUSH1', 'PUSH1', 'OP_90', 'SLOAD', 'OP_90', 'PUSH2', 'EXP', 'OP_90', 'DIV', 'PUSH20', 'AND', 'OP_82', 'OP_84', 'PUSH20', 'AND', 'PUSH2', 'OP_90', 'OP_92', 'OP_91', 'OP_90', 'PUSH4', 'AND', 'JUMP']
block 949 952
['JUMPDEST', 'POP', 'POP', 'JUMP']
block 953 1003
['JUMPDEST', 'PUSH2', 'OP_83', 'OP_84', 'PUSH20', 'AND', 'PUSH4', 'OP_85', 'OP_85', 'PUSH1', 'MLOAD', 'PUSH1', 'ADD', 'PUSH2', 'OP_92', 'OP_91', 'OP_90', 'PUSH2', 'JUMP']
block 1004 1074
['JUMPDEST', 'PUSH1', 'MLOAD', 'PUSH1', 'OP_81', 'OP_83', 'SUB', 'SUB', 'OP_81', 'MSTORE', 'OP_90', 'PUSH1', 'MSTORE', 'OP_91', 'POP', 'PUSH1', 'SHL', 'PUSH1', 'OP_82', 'ADD', 'OP_80', 'MLOAD', 'PUSH28', 'OP_83', 'OP_81', 'OP_83', 'AND', 'OR', 'OP_83', 'MSTORE', 'POP', 'POP', 'POP', 'POP', 'PUSH2', 'JUMP']
block 1075 1079
['JUMPDEST', 'POP', 'POP', 'POP', 'JUMP']
block 1080 1103
['JUMPDEST', 'PUSH1', 'OP_80', 'PUSH1', 'PUSH1', 'OP_84', 'MLOAD', 'PUSH1', 'OP_86', 'ADD', 'PUSH1', 'OP_88', 'GAS', 'CALL', 'OP_80', 'PUSH2', 'JUMPI']
block 1104 1114
['PUSH1', 'MLOAD', 'RETURNDATASIZE', 'PUSH1', 'OP_82', 'RETURNDATACOPY', 'RETURNDATASIZE', 'OP_81', 'REVERT']

thinking
**Analyzing jump destinations and access control**
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict, deque
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
adj=defaultdict(list)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    adj[e['from']].append(e['to'])
# find block ids for guard pcs 416 and 786 (within blocks 358-443 and 728-813)
pcs=[416,786]
for pc in pcs:
    guard_block=None
    for b in blocks:
        s,e=b.get('start_pc'),b.get('end_pc')
        if s is not None and e is not None and s<=pc<=e:
            guard_block=b
            break
    gid=guard_block.get('id') or f\"bb:{guard_block.get('start_pc')}\"
    print('guard pc',pc,'block',gid)
    # find which entry reaches this block
    entry_starts=[90,133,156,199,242]
    entry_ids=[f\"bb:{s}\" for s in entry_starts]
    for entry in entry_ids:
        q=deque([entry]); seen=set([entry]); found=False
        while q and not found:
            cur=q.popleft()
            if cur==gid:
                found=True; break
            for nxt in adj.get(cur,[]):
                if nxt not in seen:
                    seen.add(nxt); q.append(nxt)
        if found:
            print('  reachable from',entry)
PY" in /tmp/codex-86npeb2q succeeded in 69ms:
guard pc 416 block bb:358
  reachable from bb:133
guard pc 786 block bb:728

thinking
**Analyzing function guard reachability**
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict, deque
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
adj=defaultdict(list)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    adj[e['from']].append(e['to'])
# find block id for guard 728
for b in blocks:
    s,e=b.get('start_pc'),b.get('end_pc')
    if s is not None and e is not None and s<=786<=e:
        guard_id=b.get('id') or f\"bb:{s}\"
        break
print('guard id',guard_id)
# check reachability from bb:953 or bb:1004 to guard
for entry in ['bb:953','bb:1004','bb:872']:
    q=deque([entry]); seen=set([entry]); found=False
    while q and not found:
        cur=q.popleft()
        if cur==guard_id:
            found=True; break
        for nxt in adj.get(cur,[]):
            if nxt not in seen:
                seen.add(nxt); q.append(nxt)
    print(entry,'reaches guard',found)
# also check if guard leads to call 1098
# find call block id
call_id=None
for b in blocks:
    s,e=b.get('start_pc'),b.get('end_pc')
    if s is not None and e is not None and s<=1098<=e:
        call_id=b.get('id') or f\"bb:{s}\"; break
for entry in ['bb:728','bb:872','bb:953','bb:1004']:
    q=deque([entry]); seen=set([entry]); found=False
    while q and not found:
        cur=q.popleft()
        if cur==call_id:
            found=True; break
        for nxt in adj.get(cur,[]):
            if nxt not in seen:
                seen.add(nxt); q.append(nxt)
    print(entry,'reaches call',found)
PY" in /tmp/codex-86npeb2q succeeded in 62ms:
guard id bb:728
bb:953 reaches guard False
bb:1004 reaches guard False
bb:872 reaches guard False
bb:728 reaches call False
bb:872 reaches call False
bb:953 reaches call False
bb:1004 reaches call True

thinking
**Analyzing control flow and access checks**

I'm examining the control flow graph to see if the call at block 1098 is properly guarded or publicly accessible. The CFG might miss edges due to dynamic jumps, making the call potentially unguarded and risky. I’m checking related blocks for access control, like inspections for msg.sender checks and timestamp guards, and trying to clarify if the call target is constant or computed, which affects security risk.
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict, deque
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
adj=defaultdict(list)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    adj[e['from']].append(e['to'])
# find blocks with TIMESTAMP
timestamp_blocks=[]
for b in blocks:
    if b.get('opcodes') and 'TIMESTAMP' in b['opcodes']:
        timestamp_blocks.append(b)
print('timestamp blocks:',[(b.get('start_pc'),b.get('end_pc')) for b in timestamp_blocks])
# check reachability from entries
entry_starts=[90,133,156,199,242]
entry_ids=[f\"bb:{s}\" for s in entry_starts]
for b in timestamp_blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    print('block',bid,'start',b.get('start_pc'))
    for entry in entry_ids:
        q=deque([entry]); seen=set([entry]); found=False
        while q and not found:
            cur=q.popleft()
            if cur==bid:
                found=True; break
            for nxt in adj.get(cur,[]):
                if nxt not in seen:
                    seen.add(nxt); q.append(nxt)
        if found:
            print('  reachable from',entry)
PY" in /tmp/codex-86npeb2q succeeded in 79ms:
timestamp blocks: [(289, 299), (609, 620), (659, 669)]
block bb:289 start 289
  reachable from bb:133
block bb:609 start 609
  reachable from bb:156
block bb:659 start 659

thinking
**Analyzing function reachability and dispatch structure**
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict, deque
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
adj=defaultdict(list)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    adj[e['from']].append(e['to'])
entry_ids=[f\"bb:{s}\" for s in [90,133,156,199,242]]
for entry in entry_ids:
    q=deque([entry]); seen=set([entry]); found=False
    while q and not found:
        cur=q.popleft()
        if cur=='bb:1004':
            found=True; break
        for nxt in adj.get(cur,[]):
            if nxt not in seen:
                seen.add(nxt); q.append(nxt)
    print(entry,'reaches bb:1004',found)
PY" in /tmp/codex-86npeb2q succeeded in 42ms:
bb:90 reaches bb:1004 False
bb:133 reaches bb:1004 False
bb:156 reaches bb:1004 False
bb:199 reaches bb:1004 False
bb:242 reaches bb:1004 False

thinking
**Investigating unreachable call possibility**
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict, deque
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
adj=defaultdict(list)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    adj[e['from']].append(e['to'])
entry_ids=[f\"bb:{s}\" for s in [90,133,156,199,242]]
for target in ['bb:872','bb:953','bb:1004','bb:1080']:
    print('target',target)
    for entry in entry_ids:
        q=deque([entry]); seen=set([entry]); found=False
        while q and not found:
            cur=q.popleft()
            if cur==target:
                found=True; break
            for nxt in adj.get(cur,[]):
                if nxt not in seen:
                    seen.add(nxt); q.append(nxt)
        if found:
            print('  reachable from',entry)
PY" in /tmp/codex-86npeb2q succeeded in 27ms:
target bb:872
target bb:953
target bb:1004
target bb:1080

thinking
**Analyzing potential external call risks**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
for s in [90,133,156,199,242]:
    for b in blocks:
        if b.get('start_pc')==s:
            print('entry',s,'block',b)
            break
PY" in /tmp/codex-86npeb2q succeeded in 24ms:
entry 90 block {'end_pc': 97, 'hash': '0xf3390630a44395cb6955e033b71fc24f358093e47b3892217eebdc03dd9d7ecb', 'opcodes': ['JUMPDEST', 'CALLVALUE', 'OP_80', 'ISZERO', 'PUSH2', 'JUMPI'], 'start_pc': 90}
entry 133 block {'end_pc': 140, 'hash': '0xfc809ed105a16fcfa37b0c3848197ffd55d12f8a97d2bb87625519634c594f41', 'opcodes': ['JUMPDEST', 'CALLVALUE', 'OP_80', 'ISZERO', 'PUSH2', 'JUMPI'], 'start_pc': 133}
entry 156 block {'end_pc': 163, 'hash': '0x0042ba403c0ea2b444d07a830d935b4b2a8d19b20eeaa30630cf09bdd254e24a', 'opcodes': ['JUMPDEST', 'CALLVALUE', 'OP_80', 'ISZERO', 'PUSH2', 'JUMPI'], 'start_pc': 156}
entry 199 block {'end_pc': 206, 'hash': '0xb8115f9d429165244f69142578786d138fd0e2793f347bf1d424cefa37344cb1', 'opcodes': ['JUMPDEST', 'CALLVALUE', 'OP_80', 'ISZERO', 'PUSH2', 'JUMPI'], 'start_pc': 199}
entry 242 block {'end_pc': 249, 'hash': '0x21618fb536719e05c47be2195cf35203989f4dedcffb885cc2bfb85f00a0b8dc', 'opcodes': ['JUMPDEST', 'CALLVALUE', 'OP_80', 'ISZERO', 'PUSH2', 'JUMPI'], 'start_pc': 242}

thinking
**Analyzing entry jump targets**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
edges=j['analysis_artifact']['artifact_json']['cfg_edges']
for entry in [90,133,156,199,242]:
    bid=f\"bb:{entry}\"
    outs=[e for e in edges if e['from']==bid]
    print('entry',entry,'outs',[(id_map[o['to']].get('start_pc'),o['type']) for o in outs])
PY" in /tmp/codex-86npeb2q succeeded in 40ms:
entry 90 outs [(102, 'control_flow'), (98, 'control_flow_fallthrough')]
entry 133 outs [(145, 'control_flow'), (141, 'control_flow_fallthrough')]
entry 156 outs [(168, 'control_flow'), (164, 'control_flow_fallthrough')]
entry 199 outs [(211, 'control_flow'), (207, 'control_flow_fallthrough')]
entry 242 outs [(254, 'control_flow'), (250, 'control_flow_fallthrough')]

thinking
**Tracing entries through blocks**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
for s in [102,145,168,211,254]:
    for b in blocks:
        if b.get('start_pc')==s:
            print('block',s,b.get('end_pc'),b.get('opcodes'))
            break
PY" in /tmp/codex-86npeb2q succeeded in 38ms:
block 102 110 ['JUMPDEST', 'POP', 'PUSH2', 'PUSH2', 'JUMP']
block 145 153 ['JUMPDEST', 'POP', 'PUSH2', 'PUSH2', 'JUMP']
block 168 176 ['JUMPDEST', 'POP', 'PUSH2', 'PUSH2', 'JUMP']
block 211 219 ['JUMPDEST', 'POP', 'PUSH2', 'PUSH2', 'JUMP']
block 254 275 ['JUMPDEST', 'POP', 'PUSH2', 'PUSH1', 'OP_80', 'CALLDATASIZE', 'SUB', 'OP_81', 'ADD', 'OP_90', 'PUSH2', 'OP_91', 'OP_90', 'PUSH2', 'JUMP']

thinking
**Analyzing jump instructions and destinations**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
edges=j['analysis_artifact']['artifact_json']['cfg_edges']
for s in [102,145,168,211,254]:
    bid=f\"bb:{s}\"
    outs=[e for e in edges if e['from']==bid]
    print('from',s,'outs',[(id_map[o['to']].get('start_pc'),o['type']) for o in outs])
PY" in /tmp/codex-86npeb2q succeeded in 27ms:
from 102 outs [(283, 'control_flow')]
from 145 outs [(289, 'control_flow')]
from 168 outs [(609, 'control_flow')]
from 211 outs [(621, 'control_flow')]
from 254 outs [(1551, 'control_flow')]

thinking
**Tracing function call paths**
exec
/bin/bash -lc "python - <<'PY'
import json
from collections import defaultdict, deque
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
# map id
id_map={}
for b in blocks:
    bid=b.get('id') or f\"bb:{b.get('start_pc')}\"
    id_map[bid]=b
adj=defaultdict(list)
for e in j['analysis_artifact']['artifact_json']['cfg_edges']:
    adj[e['from']].append(e['to'])
# find call block id
call_id=None
for b in blocks:
    s,e=b.get('start_pc'),b.get('end_pc')
    if s is not None and e is not None and s<=1098<=e:
        call_id=b.get('id') or f\"bb:{s}\"; break
# BFS from bb:1551
start='bb:1551'
q=deque([start]); seen=set([start]); found=False
while q and not found:
    cur=q.popleft()
    if cur==call_id:
        found=True; break
    for nxt in adj.get(cur,[]):
        if nxt not in seen:
            seen.add(nxt); q.append(nxt)
print('bb:1551 reaches call',found)
PY" in /tmp/codex-86npeb2q succeeded in 27ms:
bb:1551 reaches call False

thinking
**Investigating unreachable call and jump tables**
exec
/bin/bash -lc "python - <<'PY'
import json
j=json.load(open('BYTECODE_BUNDLE.json'))
blocks=j['analysis_artifact']['artifact_json']['basic_blocks']
for s in [1551,1566,1574,1588,1605,1615,1632,1673,1686,1697,1708,1733,1740,1781,1794,1805,1816,1841,1848,1857,1863,1884,1897,1904,1925,1932]:
    for b in blocks:
        if b.get('start_pc')==s:
            print('block',s,'end',b.get('end_pc'), 'ops', b.get('opcodes'))
            break
PY" in /tmp/codex-86npeb2q succeeded in 42ms:
block 1551 end 1565 ops ['JUMPDEST', 'PUSH1', 'OP_80', 'PUSH1', 'OP_83', 'OP_85', 'SUB', 'SLT', 'ISZERO', 'PUSH2', 'JUMPI']
block 1566 end 1572 ops ['PUSH2', 'PUSH2', 'JUMP']
block 1574 end 1587 ops ['JUMPDEST', 'PUSH1', 'PUSH2', 'OP_85', 'OP_82', 'OP_86', 'ADD', 'PUSH2', 'JUMP']
block 1588 end 1604 ops ['JUMPDEST', 'OP_92', 'POP', 'POP', 'PUSH1', 'PUSH2', 'OP_85', 'OP_82', 'OP_86', 'ADD', 'PUSH2', 'JUMP']
block 1605 end 1614 ops ['JUMPDEST', 'OP_91', 'POP', 'POP', 'OP_92', 'POP', 'OP_92', 'OP_90', 'POP', 'JUMP']
block 1615 end 1631 ops ['JUMPDEST', 'PUSH1', 'OP_82', 'OP_82', 'MSTORE', 'PUSH1', 'OP_82', 'ADD', 'OP_90', 'POP', 'OP_92', 'OP_91', 'POP', 'POP', 'JUMP']
block 1632 end 1672 ops ['JUMPDEST', 'PUSH32', 'PUSH1', 'OP_82', 'ADD', 'MSTORE', 'POP', 'JUMP']
block 1673 end 1685 ops ['JUMPDEST', 'PUSH1', 'PUSH2', 'PUSH1', 'OP_83', 'PUSH2', 'JUMP']
block 1686 end 1696 ops ['JUMPDEST', 'OP_91', 'POP', 'PUSH2', 'OP_82', 'PUSH2', 'JUMP']
block 1697 end 1707 ops ['JUMPDEST', 'PUSH1', 'OP_82', 'ADD', 'OP_90', 'POP', 'OP_91', 'OP_90', 'POP', 'JUMP']
block 1708 end 1732 ops ['JUMPDEST', 'PUSH1', 'PUSH1', 'OP_82', 'ADD', 'OP_90', 'POP', 'OP_81', 'OP_81', 'SUB', 'PUSH1', 'OP_83', 'ADD', 'MSTORE', 'PUSH2', 'OP_81', 'PUSH2', 'JUMP']
block 1733 end 1739 ops ['JUMPDEST', 'OP_90', 'POP', 'OP_91', 'OP_90', 'POP', 'JUMP']
block 1740 end 1780 ops ['JUMPDEST', 'PUSH32', 'PUSH1', 'OP_82', 'ADD', 'MSTORE', 'POP', 'JUMP']
block 1781 end 1793 ops ['JUMPDEST', 'PUSH1', 'PUSH2', 'PUSH1', 'OP_83', 'PUSH2', 'JUMP']
block 1794 end 1804 ops ['JUMPDEST', 'OP_91', 'POP', 'PUSH2', 'OP_82', 'PUSH2', 'JUMP']
block 1805 end 1815 ops ['JUMPDEST', 'PUSH1', 'OP_82', 'ADD', 'OP_90', 'POP', 'OP_91', 'OP_90', 'POP', 'JUMP']
block 1816 end 1840 ops ['JUMPDEST', 'PUSH1', 'PUSH1', 'OP_82', 'ADD', 'OP_90', 'POP', 'OP_81', 'OP_81', 'SUB', 'PUSH1', 'OP_83', 'ADD', 'MSTORE', 'PUSH2', 'OP_81', 'PUSH2', 'JUMP']
block 1841 end 1847 ops ['JUMPDEST', 'OP_90', 'POP', 'OP_91', 'OP_90', 'POP', 'JUMP']
block 1848 end 1856 ops ['JUMPDEST', 'PUSH2', 'OP_81', 'PUSH2', 'JUMP']
block 1857 end 1862 ops ['JUMPDEST', 'OP_82', 'MSTORE', 'POP', 'POP', 'JUMP']

thinking
**Summarizing bytecode security findings**

This analysis inspects two low-level CALLs with computed targets and values in the bytecode, highlighting uncertainty about reachability and access control. One call seems owner/time-locked and the other potentially unguarded, allowing arbitrary external calls with ETH transfer if reachable. I’m weighing severity as low to medium due to incomplete control-flow data, noting the lack of explicit caller checks near the second callsite and absence of delegatecall or storage writes, which limits risks. I'll consolidate these points into a JSON finding emphasizing potential unguarded calls, necessary guard checks, and uncertainty around dynamic jump paths.
codex
{"no_findings":false,"summary":"Two low-level CALL sites exist with computed target/value; one appears owner/time-locked, while the reachability/guarding of the pc:0x44a CALL is unclear from the bytecode graph and could allow arbitrary external calls if exposed.","findings":[{"severity":"medium","category":"access_control","title":"Potentially unguarded arbitrary CALL with ETH value (reachability unclear)","exploit_scenario":"If the code path containing the CALL at pc:0x44a (1098) is reachable from a public selector and its target/value are derived from calldata or other user-controlled inputs, any caller could trigger arbitrary external calls (and potentially transfer ETH) from this contract. This could allow draining ETH, token approvals/transfers, or interaction with attacker-controlled contracts. However, the control-flow graph does not clearly link this block to the dispatcher, and one dynamic trace observed a constant target (self), so actual exploitability is uncertain.","recommendation":"Confirm whether the pc:0x44a call path is reachable from any external selector and whether its target/value are user-controlled. If reachable, add explicit access control (owner/time-lock/allowlist) and validate target/value. If the call is intended to be a self-call or a fixed target, hardcode it or add assertions to prevent user-controlled targets.","evidence":"Bytecode analysis shows CALL at pc 1098 with target/value classified as computed (`callsites`), and no CALLER-based guard appears in nearby blocks (pc 953/1004/1080). Detector flagged both \"Untrusted CALL target/value reachable\" and \"ETH value transfer possible\" for this callsite; validation trace observed a constant target (self), so control is uncertain.","locations":["pc:0x44a","pc:0x3b8","pc:0x3ec"]}]}
tokens used
104,768
Metadata
{
    "codex": {
        "ran_at": "2026-01-11T06:29:05.070471+00:00",
        "returncode": 0
    },
    "project": {
        "mode": "bytecode",
        "bytecode_length": 3972,
        "bytecode_truncated": false,
        "capability_graph_present": true,
        "analysis_artifact_present": true
    },
    "summary": "Two low-level CALL sites exist with computed target/value; one appears owner/time-locked, while the reachability/guarding of the pc:0x44a CALL is unclear from the bytecode graph and could allow arbitrary external calls if exposed.",
    "raw_final": {
        "summary": "Two low-level CALL sites exist with computed target/value; one appears owner/time-locked, while the reachability/guarding of the pc:0x44a CALL is unclear from the bytecode graph and could allow arbitrary external calls if exposed.",
        "findings": [
            {
                "title": "Potentially unguarded arbitrary CALL with ETH value (reachability unclear)",
                "category": "access_control",
                "evidence": "Bytecode analysis shows CALL at pc 1098 with target/value classified as computed (`callsites`), and no CALLER-based guard appears in nearby blocks (pc 953/1004/1080). Detector flagged both \"Untrusted CALL target/value reachable\" and \"ETH value transfer possible\" for this callsite; validation trace observed a constant target (self), so control is uncertain.",
                "severity": "medium",
                "locations": [
                    "pc:0x44a",
                    "pc:0x3b8",
                    "pc:0x3ec"
                ],
                "recommendation": "Confirm whether the pc:0x44a call path is reachable from any external selector and whether its target/value are user-controlled. If reachable, add explicit access control (owner/time-lock/allowlist) and validate target/value. If the call is intended to be a self-call or a fixed target, hardcode it or add assertions to prevent user-controlled targets.",
                "exploit_scenario": "If the code path containing the CALL at pc:0x44a (1098) is reachable from a public selector and its target/value are derived from calldata or other user-controlled inputs, any caller could trigger arbitrary external calls (and potentially transfer ETH) from this contract. This could allow draining ETH, token approvals/transfers, or interaction with attacker-controlled contracts. However, the control-flow graph does not clearly link this block to the dispatcher, and one dynamic trace observed a constant target (self), so actual exploitability is uncertain."
            }
        ],
        "no_findings": false
    },
    "no_findings": false,
    "schema_version": 1
}

Opcode Heuristics

tool.cast_disasm
Delegatecall
0
Selfdestruct
0
CREATE2
0
CALL-family (heavy)
2
EXT*/BALANCE
1
Total opcodes
1044
Flags
No heuristic flags raised.
View cast disassembly output
00000000: PUSH1 0x80
00000002: PUSH1 0x40
00000004: MSTORE
00000005: PUSH1 0x04
00000007: CALLDATASIZE
00000008: LT
00000009: PUSH2 0x004e
0000000c: JUMPI
0000000d: PUSH1 0x00
0000000f: CALLDATALOAD
00000010: PUSH1 0xe0
00000012: SHR
00000013: DUP1
00000014: PUSH4 0x251c1aa3
00000019: EQ
0000001a: PUSH2 0x005a
0000001d: JUMPI
0000001e: DUP1
0000001f: PUSH4 0x3ccfd60b
00000024: EQ
00000025: PUSH2 0x0085
00000028: JUMPI
00000029: DUP1
0000002a: PUSH4 0x8380edb7
0000002f: EQ
00000030: PUSH2 0x009c
00000033: JUMPI
00000034: DUP1
00000035: PUSH4 0x8da5cb5b
0000003a: EQ
0000003b: PUSH2 0x00c7
0000003e: JUMPI
0000003f: DUP1
00000040: PUSH4 0xa1db9782
00000045: EQ
00000046: PUSH2 0x00f2
00000049: JUMPI
0000004a: PUSH2 0x0055
0000004d: JUMP
0000004e: JUMPDEST
0000004f: CALLDATASIZE
00000050: PUSH2 0x0055
00000053: JUMPI
00000054: STOP
00000055: JUMPDEST
00000056: PUSH1 0x00
00000058: DUP1
00000059: REVERT
0000005a: JUMPDEST
0000005b: CALLVALUE
0000005c: DUP1
0000005d: ISZERO
0000005e: PUSH2 0x0066
00000061: JUMPI
00000062: PUSH1 0x00
00000064: DUP1
00000065: REVERT
00000066: JUMPDEST
00000067: POP
00000068: PUSH2 0x006f
0000006b: PUSH2 0x011b
0000006e: JUMP
0000006f: JUMPDEST
00000070: PUSH1 0x40
00000072: MLOAD
00000073: PUSH2 0x007c
00000076: SWAP2
00000077: SWAP1
00000078: PUSH2 0x04f3
0000007b: JUMP
0000007c: JUMPDEST
0000007d: PUSH1 0x40
0000007f: MLOAD
00000080: DUP1
00000081: SWAP2
00000082: SUB
00000083: SWAP1
00000084: RETURN
00000085: JUMPDEST
00000086: CALLVALUE
00000087: DUP1
00000088: ISZERO
00000089: PUSH2 0x0091
0000008c: JUMPI
0000008d: PUSH1 0x00
0000008f: DUP1
00000090: REVERT
00000091: JUMPDEST
00000092: POP
00000093: PUSH2 0x009a
00000096: PUSH2 0x0121
00000099: JUMP
0000009a: JUMPDEST
0000009b: STOP
0000009c: JUMPDEST
0000009d: CALLVALUE
0000009e: DUP1
0000009f: ISZERO
000000a0: PUSH2 0x00a8
000000a3: JUMPI
000000a4: PUSH1 0x00
000000a6: DUP1
000000a7: REVERT
000000a8: JUMPDEST
000000a9: POP
000000aa: PUSH2 0x00b1
000000ad: PUSH2 0x0261
000000b0: JUMP
000000b1: JUMPDEST
000000b2: PUSH1 0x40
000000b4: MLOAD
000000b5: PUSH2 0x00be
000000b8: SWAP2
000000b9: SWAP1
000000ba: PUSH2 0x0529
000000bd: JUMP
000000be: JUMPDEST
000000bf: PUSH1 0x40
000000c1: MLOAD
000000c2: DUP1
000000c3: SWAP2
000000c4: SUB
000000c5: SWAP1
000000c6: RETURN
000000c7: JUMPDEST
000000c8: CALLVALUE
000000c9: DUP1
000000ca: ISZERO
000000cb: PUSH2 0x00d3
000000ce: JUMPI
000000cf: PUSH1 0x00
000000d1: DUP1
000000d2: REVERT
000000d3: JUMPDEST
000000d4: POP
000000d5: PUSH2 0x00dc
000000d8: PUSH2 0x026d
000000db: JUMP
000000dc: JUMPDEST
000000dd: PUSH1 0x40
000000df: MLOAD
000000e0: PUSH2 0x00e9
000000e3: SWAP2
000000e4: SWAP1
000000e5: PUSH2 0x0585
000000e8: JUMP
000000e9: JUMPDEST
000000ea: PUSH1 0x40
000000ec: MLOAD
000000ed: DUP1
000000ee: SWAP2
000000ef: SUB
000000f0: SWAP1
000000f1: RETURN
000000f2: JUMPDEST
000000f3: CALLVALUE
000000f4: DUP1
000000f5: ISZERO
000000f6: PUSH2 0x00fe
000000f9: JUMPI
000000fa: PUSH1 0x00
000000fc: DUP1
000000fd: REVERT
000000fe: JUMPDEST
000000ff: POP
00000100: PUSH2 0x0119
00000103: PUSH1 0x04
00000105: DUP1
00000106: CALLDATASIZE
00000107: SUB
00000108: DUP2
00000109: ADD
0000010a: SWAP1
0000010b: PUSH2 0x0114
0000010e: SWAP2
0000010f: SWAP1
00000110: PUSH2 0x060f
00000113: JUMP
00000114: JUMPDEST
00000115: PUSH2 0x0293
00000118: JUMP
00000119: JUMPDEST
0000011a: STOP
0000011b: JUMPDEST
0000011c: PUSH1 0x00
0000011e: SLOAD
0000011f: DUP2
00000120: JUMP
00000121: JUMPDEST
00000122: PUSH1 0x00
00000124: SLOAD
00000125: TIMESTAMP
00000126: LT
00000127: ISZERO
00000128: PUSH2 0x0166
0000012b: JUMPI
0000012c: PUSH1 0x40
0000012e: MLOAD
0000012f: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
00000150: DUP2
00000151: MSTORE
00000152: PUSH1 0x04
00000154: ADD
00000155: PUSH2 0x015d
00000158: SWAP1
00000159: PUSH2 0x06ac
0000015c: JUMP
0000015d: JUMPDEST
0000015e: PUSH1 0x40
00000160: MLOAD
00000161: DUP1
00000162: SWAP2
00000163: SUB
00000164: SWAP1
00000165: REVERT
00000166: JUMPDEST
00000167: PUSH1 0x01
00000169: PUSH1 0x00
0000016b: SWAP1
0000016c: SLOAD
0000016d: SWAP1
0000016e: PUSH2 0x0100
00000171: EXP
00000172: SWAP1
00000173: DIV
00000174: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000189: AND
0000018a: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000019f: AND
000001a0: CALLER
000001a1: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
000001b6: AND
000001b7: EQ
000001b8: PUSH2 0x01f6
000001bb: JUMPI
000001bc: PUSH1 0x40
000001be: MLOAD
000001bf: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
000001e0: DUP2
000001e1: MSTORE
000001e2: PUSH1 0x04
000001e4: ADD
000001e5: PUSH2 0x01ed
000001e8: SWAP1
000001e9: PUSH2 0x0718
000001ec: JUMP
000001ed: JUMPDEST
000001ee: PUSH1 0x40
000001f0: MLOAD
000001f1: DUP1
000001f2: SWAP2
000001f3: SUB
000001f4: SWAP1
000001f5: REVERT
000001f6: JUMPDEST
000001f7: PUSH1 0x01
000001f9: PUSH1 0x00
000001fb: SWAP1
000001fc: SLOAD
000001fd: SWAP1
000001fe: PUSH2 0x0100
00000201: EXP
00000202: SWAP1
00000203: DIV
00000204: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000219: AND
0000021a: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000022f: AND
00000230: PUSH2 0x08fc
00000233: SELFBALANCE
00000234: SWAP1
00000235: DUP2
00000236: ISZERO
00000237: MUL
00000238: SWAP1
00000239: PUSH1 0x40
0000023b: MLOAD
0000023c: PUSH1 0x00
0000023e: PUSH1 0x40
00000240: MLOAD
00000241: DUP1
00000242: DUP4
00000243: SUB
00000244: DUP2
00000245: DUP6
00000246: DUP9
00000247: DUP9
00000248: CALL
00000249: SWAP4
0000024a: POP
0000024b: POP
0000024c: POP
0000024d: POP
0000024e: ISZERO
0000024f: DUP1
00000250: ISZERO
00000251: PUSH2 0x025e
00000254: JUMPI
00000255: RETURNDATASIZE
00000256: PUSH1 0x00
00000258: DUP1
00000259: RETURNDATACOPY
0000025a: RETURNDATASIZE
0000025b: PUSH1 0x00
0000025d: REVERT
0000025e: JUMPDEST
0000025f: POP
00000260: JUMP
00000261: JUMPDEST
00000262: PUSH1 0x00
00000264: DUP1
00000265: SLOAD
00000266: TIMESTAMP
00000267: LT
00000268: ISZERO
00000269: SWAP1
0000026a: POP
0000026b: SWAP1
0000026c: JUMP
0000026d: JUMPDEST
0000026e: PUSH1 0x01
00000270: PUSH1 0x00
00000272: SWAP1
00000273: SLOAD
00000274: SWAP1
00000275: PUSH2 0x0100
00000278: EXP
00000279: SWAP1
0000027a: DIV
0000027b: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000290: AND
00000291: DUP2
00000292: JUMP
00000293: JUMPDEST
00000294: PUSH1 0x00
00000296: SLOAD
00000297: TIMESTAMP
00000298: LT
00000299: ISZERO
0000029a: PUSH2 0x02d8
0000029d: JUMPI
0000029e: PUSH1 0x40
000002a0: MLOAD
000002a1: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
000002c2: DUP2
000002c3: MSTORE
000002c4: PUSH1 0x04
000002c6: ADD
000002c7: PUSH2 0x02cf
000002ca: SWAP1
000002cb: PUSH2 0x06ac
000002ce: JUMP
000002cf: JUMPDEST
000002d0: PUSH1 0x40
000002d2: MLOAD
000002d3: DUP1
000002d4: SWAP2
000002d5: SUB
000002d6: SWAP1
000002d7: REVERT
000002d8: JUMPDEST
000002d9: PUSH1 0x01
000002db: PUSH1 0x00
000002dd: SWAP1
000002de: SLOAD
000002df: SWAP1
000002e0: PUSH2 0x0100
000002e3: EXP
000002e4: SWAP1
000002e5: DIV
000002e6: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
000002fb: AND
000002fc: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000311: AND
00000312: CALLER
00000313: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000328: AND
00000329: EQ
0000032a: PUSH2 0x0368
0000032d: JUMPI
0000032e: PUSH1 0x40
00000330: MLOAD
00000331: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
00000352: DUP2
00000353: MSTORE
00000354: PUSH1 0x04
00000356: ADD
00000357: PUSH2 0x035f
0000035a: SWAP1
0000035b: PUSH2 0x0718
0000035e: JUMP
0000035f: JUMPDEST
00000360: PUSH1 0x40
00000362: MLOAD
00000363: DUP1
00000364: SWAP2
00000365: SUB
00000366: SWAP1
00000367: REVERT
00000368: JUMPDEST
00000369: PUSH2 0x03b5
0000036c: PUSH1 0x01
0000036e: PUSH1 0x00
00000370: SWAP1
00000371: SLOAD
00000372: SWAP1
00000373: PUSH2 0x0100
00000376: EXP
00000377: SWAP1
00000378: DIV
00000379: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000038e: AND
0000038f: DUP3
00000390: DUP5
00000391: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
000003a6: AND
000003a7: PUSH2 0x03b9
000003aa: SWAP1
000003ab: SWAP3
000003ac: SWAP2
000003ad: SWAP1
000003ae: PUSH4 0xffffffff
000003b3: AND
000003b4: JUMP
000003b5: JUMPDEST
000003b6: POP
000003b7: POP
000003b8: JUMP
000003b9: JUMPDEST
000003ba: PUSH2 0x0433
000003bd: DUP4
000003be: DUP5
000003bf: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
000003d4: AND
000003d5: PUSH4 0xa9059cbb
000003da: DUP6
000003db: DUP6
000003dc: PUSH1 0x40
000003de: MLOAD
000003df: PUSH1 0x24
000003e1: ADD
000003e2: PUSH2 0x03ec
000003e5: SWAP3
000003e6: SWAP2
000003e7: SWAP1
000003e8: PUSH2 0x0747
000003eb: JUMP
000003ec: JUMPDEST
000003ed: PUSH1 0x40
000003ef: MLOAD
000003f0: PUSH1 0x20
000003f2: DUP2
000003f3: DUP4
000003f4: SUB
000003f5: SUB
000003f6: DUP2
000003f7: MSTORE
000003f8: SWAP1
000003f9: PUSH1 0x40
000003fb: MSTORE
000003fc: SWAP2
000003fd: POP
000003fe: PUSH1 0xe0
00000400: SHL
00000401: PUSH1 0x20
00000403: DUP3
00000404: ADD
00000405: DUP1
00000406: MLOAD
00000407: PUSH28 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff
00000424: DUP4
00000425: DUP2
00000426: DUP4
00000427: AND
00000428: OR
00000429: DUP4
0000042a: MSTORE
0000042b: POP
0000042c: POP
0000042d: POP
0000042e: POP
0000042f: PUSH2 0x0438
00000432: JUMP
00000433: JUMPDEST
00000434: POP
00000435: POP
00000436: POP
00000437: JUMP
00000438: JUMPDEST
00000439: PUSH1 0x00
0000043b: DUP1
0000043c: PUSH1 0x20
0000043e: PUSH1 0x00
00000440: DUP5
00000441: MLOAD
00000442: PUSH1 0x20
00000444: DUP7
00000445: ADD
00000446: PUSH1 0x00
00000448: DUP9
00000449: GAS
0000044a: CALL
0000044b: DUP1
0000044c: PUSH2 0x045b
0000044f: JUMPI
00000450: PUSH1 0x40
00000452: MLOAD
00000453: RETURNDATASIZE
00000454: PUSH1 0x00
00000456: DUP3
00000457: RETURNDATACOPY
00000458: RETURNDATASIZE
00000459: DUP2
0000045a: REVERT
0000045b: JUMPDEST
0000045c: RETURNDATASIZE
0000045d: SWAP3
0000045e: POP
0000045f: PUSH1 0x00
00000461: MLOAD
00000462: SWAP2
00000463: POP
00000464: POP
00000465: PUSH1 0x00
00000467: DUP3
00000468: EQ
00000469: PUSH2 0x0476
0000046c: JUMPI
0000046d: PUSH1 0x01
0000046f: DUP2
00000470: EQ
00000471: ISZERO
00000472: PUSH2 0x0492
00000475: JUMP
00000476: JUMPDEST
00000477: PUSH1 0x00
00000479: DUP5
0000047a: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000048f: AND
00000490: EXTCODESIZE
00000491: EQ
00000492: JUMPDEST
00000493: ISZERO
00000494: PUSH2 0x04d4
00000497: JUMPI
00000498: DUP4
00000499: PUSH1 0x40
0000049b: MLOAD
0000049c: PUSH32 0x5274afe700000000000000000000000000000000000000000000000000000000
000004bd: DUP2
000004be: MSTORE
000004bf: PUSH1 0x04
000004c1: ADD
000004c2: PUSH2 0x04cb
000004c5: SWAP2
000004c6: SWAP1
000004c7: PUSH2 0x0770
000004ca: JUMP
000004cb: JUMPDEST
000004cc: PUSH1 0x40
000004ce: MLOAD
000004cf: DUP1
000004d0: SWAP2
000004d1: SUB
000004d2: SWAP1
000004d3: REVERT
000004d4: JUMPDEST
000004d5: POP
000004d6: POP
000004d7: POP
000004d8: POP
000004d9: JUMP
000004da: JUMPDEST
000004db: PUSH1 0x00
000004dd: DUP2
000004de: SWAP1
000004df: POP
000004e0: SWAP2
000004e1: SWAP1
000004e2: POP
000004e3: JUMP
000004e4: JUMPDEST
000004e5: PUSH2 0x04ed
000004e8: DUP2
000004e9: PUSH2 0x04da
000004ec: JUMP
000004ed: JUMPDEST
000004ee: DUP3
000004ef: MSTORE
000004f0: POP
000004f1: POP
000004f2: JUMP
000004f3: JUMPDEST
000004f4: PUSH1 0x00
000004f6: PUSH1 0x20
000004f8: DUP3
000004f9: ADD
000004fa: SWAP1
000004fb: POP
000004fc: PUSH2 0x0508
000004ff: PUSH1 0x00
00000501: DUP4
00000502: ADD
00000503: DUP5
00000504: PUSH2 0x04e4
00000507: JUMP
00000508: JUMPDEST
00000509: SWAP3
0000050a: SWAP2
0000050b: POP
0000050c: POP
0000050d: JUMP
0000050e: JUMPDEST
0000050f: PUSH1 0x00
00000511: DUP2
00000512: ISZERO
00000513: ISZERO
00000514: SWAP1
00000515: POP
00000516: SWAP2
00000517: SWAP1
00000518: POP
00000519: JUMP
0000051a: JUMPDEST
0000051b: PUSH2 0x0523
0000051e: DUP2
0000051f: PUSH2 0x050e
00000522: JUMP
00000523: JUMPDEST
00000524: DUP3
00000525: MSTORE
00000526: POP
00000527: POP
00000528: JUMP
00000529: JUMPDEST
0000052a: PUSH1 0x00
0000052c: PUSH1 0x20
0000052e: DUP3
0000052f: ADD
00000530: SWAP1
00000531: POP
00000532: PUSH2 0x053e
00000535: PUSH1 0x00
00000537: DUP4
00000538: ADD
00000539: DUP5
0000053a: PUSH2 0x051a
0000053d: JUMP
0000053e: JUMPDEST
0000053f: SWAP3
00000540: SWAP2
00000541: POP
00000542: POP
00000543: JUMP
00000544: JUMPDEST
00000545: PUSH1 0x00
00000547: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000055c: DUP3
0000055d: AND
0000055e: SWAP1
0000055f: POP
00000560: SWAP2
00000561: SWAP1
00000562: POP
00000563: JUMP
00000564: JUMPDEST
00000565: PUSH1 0x00
00000567: PUSH2 0x056f
0000056a: DUP3
0000056b: PUSH2 0x0544
0000056e: JUMP
0000056f: JUMPDEST
00000570: SWAP1
00000571: POP
00000572: SWAP2
00000573: SWAP1
00000574: POP
00000575: JUMP
00000576: JUMPDEST
00000577: PUSH2 0x057f
0000057a: DUP2
0000057b: PUSH2 0x0564
0000057e: JUMP
0000057f: JUMPDEST
00000580: DUP3
00000581: MSTORE
00000582: POP
00000583: POP
00000584: JUMP
00000585: JUMPDEST
00000586: PUSH1 0x00
00000588: PUSH1 0x20
0000058a: DUP3
0000058b: ADD
0000058c: SWAP1
0000058d: POP
0000058e: PUSH2 0x059a
00000591: PUSH1 0x00
00000593: DUP4
00000594: ADD
00000595: DUP5
00000596: PUSH2 0x0576
00000599: JUMP
0000059a: JUMPDEST
0000059b: SWAP3
0000059c: SWAP2
0000059d: POP
0000059e: POP
0000059f: JUMP
000005a0: JUMPDEST
000005a1: PUSH1 0x00
000005a3: DUP1
000005a4: REVERT
000005a5: JUMPDEST
000005a6: PUSH1 0x00
000005a8: PUSH2 0x05b0
000005ab: DUP3
000005ac: PUSH2 0x0544
000005af: JUMP
000005b0: JUMPDEST
000005b1: SWAP1
000005b2: POP
000005b3: SWAP2
000005b4: SWAP1
000005b5: POP
000005b6: JUMP
000005b7: JUMPDEST
000005b8: PUSH2 0x05c0
000005bb: DUP2
000005bc: PUSH2 0x05a5
000005bf: JUMP
000005c0: JUMPDEST
000005c1: DUP2
000005c2: EQ
000005c3: PUSH2 0x05cb
000005c6: JUMPI
000005c7: PUSH1 0x00
000005c9: DUP1
000005ca: REVERT
000005cb: JUMPDEST
000005cc: POP
000005cd: JUMP
000005ce: JUMPDEST
000005cf: PUSH1 0x00
000005d1: DUP2
000005d2: CALLDATALOAD
000005d3: SWAP1
000005d4: POP
000005d5: PUSH2 0x05dd
000005d8: DUP2
000005d9: PUSH2 0x05b7
000005dc: JUMP
000005dd: JUMPDEST
000005de: SWAP3
000005df: SWAP2
000005e0: POP
000005e1: POP
000005e2: JUMP
000005e3: JUMPDEST
000005e4: PUSH2 0x05ec
000005e7: DUP2
000005e8: PUSH2 0x04da
000005eb: JUMP
000005ec: JUMPDEST
000005ed: DUP2
000005ee: EQ
000005ef: PUSH2 0x05f7
000005f2: JUMPI
000005f3: PUSH1 0x00
000005f5: DUP1
000005f6: REVERT
000005f7: JUMPDEST
000005f8: POP
000005f9: JUMP
000005fa: JUMPDEST
000005fb: PUSH1 0x00
000005fd: DUP2
000005fe: CALLDATALOAD
000005ff: SWAP1
00000600: POP
00000601: PUSH2 0x0609
00000604: DUP2
00000605: PUSH2 0x05e3
00000608: JUMP
00000609: JUMPDEST
0000060a: SWAP3
0000060b: SWAP2
0000060c: POP
0000060d: POP
0000060e: JUMP
0000060f: JUMPDEST
00000610: PUSH1 0x00
00000612: DUP1
00000613: PUSH1 0x40
00000615: DUP4
00000616: DUP6
00000617: SUB
00000618: SLT
00000619: ISZERO
0000061a: PUSH2 0x0626
0000061d: JUMPI
0000061e: PUSH2 0x0625
00000621: PUSH2 0x05a0
00000624: JUMP
00000625: JUMPDEST
00000626: JUMPDEST
00000627: PUSH1 0x00
00000629: PUSH2 0x0634
0000062c: DUP6
0000062d: DUP3
0000062e: DUP7
0000062f: ADD
00000630: PUSH2 0x05ce
00000633: JUMP
00000634: JUMPDEST
00000635: SWAP3
00000636: POP
00000637: POP
00000638: PUSH1 0x20
0000063a: PUSH2 0x0645
0000063d: DUP6
0000063e: DUP3
0000063f: DUP7
00000640: ADD
00000641: PUSH2 0x05fa
00000644: JUMP
00000645: JUMPDEST
00000646: SWAP2
00000647: POP
00000648: POP
00000649: SWAP3
0000064a: POP
0000064b: SWAP3
0000064c: SWAP1
0000064d: POP
0000064e: JUMP
0000064f: JUMPDEST
00000650: PUSH1 0x00
00000652: DUP3
00000653: DUP3
00000654: MSTORE
00000655: PUSH1 0x20
00000657: DUP3
00000658: ADD
00000659: SWAP1
0000065a: POP
0000065b: SWAP3
0000065c: SWAP2
0000065d: POP
0000065e: POP
0000065f: JUMP
00000660: JUMPDEST
00000661: PUSH32 0x596f752063616e27742077697468647261772079657400000000000000000000
00000682: PUSH1 0x00
00000684: DUP3
00000685: ADD
00000686: MSTORE
00000687: POP
00000688: JUMP
00000689: JUMPDEST
0000068a: PUSH1 0x00
0000068c: PUSH2 0x0696
0000068f: PUSH1 0x16
00000691: DUP4
00000692: PUSH2 0x064f
00000695: JUMP
00000696: JUMPDEST
00000697: SWAP2
00000698: POP
00000699: PUSH2 0x06a1
0000069c: DUP3
0000069d: PUSH2 0x0660
000006a0: JUMP
000006a1: JUMPDEST
000006a2: PUSH1 0x20
000006a4: DUP3
000006a5: ADD
000006a6: SWAP1
000006a7: POP
000006a8: SWAP2
000006a9: SWAP1
000006aa: POP
000006ab: JUMP
000006ac: JUMPDEST
000006ad: PUSH1 0x00
000006af: PUSH1 0x20
000006b1: DUP3
000006b2: ADD
000006b3: SWAP1
000006b4: POP
000006b5: DUP2
000006b6: DUP2
000006b7: SUB
000006b8: PUSH1 0x00
000006ba: DUP4
000006bb: ADD
000006bc: MSTORE
000006bd: PUSH2 0x06c5
000006c0: DUP2
000006c1: PUSH2 0x0689
000006c4: JUMP
000006c5: JUMPDEST
000006c6: SWAP1
000006c7: POP
000006c8: SWAP2
000006c9: SWAP1
000006ca: POP
000006cb: JUMP
000006cc: JUMPDEST
000006cd: PUSH32 0x596f75206172656e277420746865206f776e6572000000000000000000000000
000006ee: PUSH1 0x00
000006f0: DUP3
000006f1: ADD
000006f2: MSTORE
000006f3: POP
000006f4: JUMP
000006f5: JUMPDEST
000006f6: PUSH1 0x00
000006f8: PUSH2 0x0702
000006fb: PUSH1 0x14
000006fd: DUP4
000006fe: PUSH2 0x064f
00000701: JUMP
00000702: JUMPDEST
00000703: SWAP2
00000704: POP
00000705: PUSH2 0x070d
00000708: DUP3
00000709: PUSH2 0x06cc
0000070c: JUMP
0000070d: JUMPDEST
0000070e: PUSH1 0x20
00000710: DUP3
00000711: ADD
00000712: SWAP1
00000713: POP
00000714: SWAP2
00000715: SWAP1
00000716: POP
00000717: JUMP
00000718: JUMPDEST
00000719: PUSH1 0x00
0000071b: PUSH1 0x20
0000071d: DUP3
0000071e: ADD
0000071f: SWAP1
00000720: POP
00000721: DUP2
00000722: DUP2
00000723: SUB
00000724: PUSH1 0x00
00000726: DUP4
00000727: ADD
00000728: MSTORE
00000729: PUSH2 0x0731
0000072c: DUP2
0000072d: PUSH2 0x06f5
00000730: JUMP
00000731: JUMPDEST
00000732: SWAP1
00000733: POP
00000734: SWAP2
00000735: SWAP1
00000736: POP
00000737: JUMP
00000738: JUMPDEST
00000739: PUSH2 0x0741
0000073c: DUP2
0000073d: PUSH2 0x05a5
00000740: JUMP
00000741: JUMPDEST
00000742: DUP3
00000743: MSTORE
00000744: POP
00000745: POP
00000746: JUMP
00000747: JUMPDEST
00000748: PUSH1 0x00
0000074a: PUSH1 0x40
0000074c: DUP3
0000074d: ADD
0000074e: SWAP1
0000074f: POP
00000750: PUSH2 0x075c
00000753: PUSH1 0x00
00000755: DUP4
00000756: ADD
00000757: DUP6
00000758: PUSH2 0x0738
0000075b: JUMP
0000075c: JUMPDEST
0000075d: PUSH2 0x0769
00000760: PUSH1 0x20
00000762: DUP4
00000763: ADD
00000764: DUP5
00000765: PUSH2 0x04e4
00000768: JUMP
00000769: JUMPDEST
0000076a: SWAP4
0000076b: SWAP3
0000076c: POP
0000076d: POP
0000076e: POP
0000076f: JUMP
00000770: JUMPDEST
00000771: PUSH1 0x00
00000773: PUSH1 0x20
00000775: DUP3
00000776: ADD
00000777: SWAP1
00000778: POP
00000779: PUSH2 0x0785
0000077c: PUSH1 0x00
0000077e: DUP4
0000077f: ADD
00000780: DUP5
00000781: PUSH2 0x0738
00000784: JUMP
00000785: JUMPDEST
00000786: SWAP3
00000787: SWAP2
00000788: POP
00000789: POP
0000078a: JUMP
0000078b: INVALID
0000078c: LOG2
0000078d: PUSH5 0x6970667358
00000793: UNKNOWN(0x22)
00000794: SLT
00000795: KECCAK256
00000796: UNKNOWN(0xEB)
00000797: UNKNOWN(0xB2)
00000798: SWAP9
00000799: UNKNOWN(0xE1)
0000079a: LOG4
0000079b: UNKNOWN(0x23)
0000079c: UNKNOWN(0x23)
0000079d: UNKNOWN(0x0F)
0000079e: PUSH30 0xfbc66c1cc7991da8417383cc4afc1d56a194e84b83264864736f6c634300
000007bd: ADDMOD
000007be: SHR
000007bf: STOP
000007c0: CALLER

Findings

validated = confirmed for call sinks; sink observed for others
Severity Category Tool Title Confidence Validated Confirmed Details
medium access_control codex Potentially unguarded arbitrary CALL with ETH value (reachability unclear) 75 no
view
evidence_json
{
    "evidence": "Bytecode analysis shows CALL at pc 1098 with target/value classified as computed (`callsites`), and no CALLER-based guard appears in nearby blocks (pc 953/1004/1080). Detector flagged both \"Untrusted CALL target/value reachable\" and \"ETH value transfer possible\" for this callsite; validation trace observed a constant target (self), so control is uncertain.",
    "locations": [
        "pc:0x44a",
        "pc:0x3b8",
        "pc:0x3ec"
    ],
    "recommendation": "Confirm whether the pc:0x44a call path is reachable from any external selector and whether its target/value are user-controlled. If reachable, add explicit access control (owner/time-lock/allowlist) and validate target/value. If the call is intended to be a self-call or a fixed target, hardcode it or add assertions to prevent user-controlled targets.",
    "exploit_scenario": "If the code path containing the CALL at pc:0x44a (1098) is reachable from a public selector and its target/value are derived from calldata or other user-controlled inputs, any caller could trigger arbitrary external calls (and potentially transfer ETH) from this contract. This could allow draining ETH, token approvals/transfers, or interaction with attacker-controlled contracts. However, the control-flow graph does not clearly link this block to the dispatcher, and one dynamic trace observed a constant target (self), so actual exploitability is uncertain."
}
medium other detector Untrusted CALL target/value reachable 45 no no
view
trace_id: 0x09febf62874f57fb20e29e0f289c69e4bb05508ae453a3a747d87c873e5a727c
call_targets: 0x367ba7d034abf0b97bccdf07fd95217410c9dbe8
target_varies: no
classification: constant_target
validation_json
{
    "sink": "CALL",
    "errors": 0,
    "status": "sink_reached",
    "attempts": 1,
    "trace_id": "0x09febf62874f57fb20e29e0f289c69e4bb05508ae453a3a747d87c873e5a727c",
    "confirmed": false,
    "trace_mode": "callTracer",
    "call_targets": [
        "0x367ba7d034abf0b97bccdf07fd95217410c9dbe8"
    ],
    "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": "0x251c1aa3",
            "selector": "0x251c1aa3",
            "calldata_variants": [
                "0x251c1aa3",
                "0x251c1aa30000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0x3ccfd60b",
            "selector": "0x3ccfd60b",
            "calldata_variants": [
                "0x3ccfd60b",
                "0x3ccfd60b0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0x8380edb7",
            "selector": "0x8380edb7",
            "calldata_variants": [
                "0x8380edb7",
                "0x8380edb70000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0x8da5cb5b",
            "selector": "0x8da5cb5b",
            "calldata_variants": [
                "0x8da5cb5b",
                "0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xa1db9782",
            "selector": "0xa1db9782",
            "calldata_variants": [
                "0xa1db9782",
                "0xa1db97820000000000000000000000000000000000000000000000000000000000000000"
            ]
        }
    ]
}
evidence_json
{
    "examples": [
        {
            "pc": 584,
            "opcode": "CALL",
            "returndata_checked": null,
            "value_expression_category": "computed",
            "target_expression_category": "computed"
        },
        {
            "pc": 1098,
            "opcode": "CALL",
            "returndata_checked": null,
            "value_expression_category": "computed",
            "target_expression_category": "computed"
        }
    ],
    "call_count": 2,
    "guards_detected": [
        {
            "pc": 416,
            "type": "msg_sender_eq_const",
            "value": "0xffffffffffffffffffffffffffffffffffffffff"
        },
        {
            "pc": 786,
            "type": "msg_sender_eq_const",
            "value": "0xffffffffffffffffffffffffffffffffffffffff"
        }
    ],
    "untrusted_call_count": 2
}
medium other detector ETH value transfer possible 40 no no
view
trace_id: 0x09febf62874f57fb20e29e0f289c69e4bb05508ae453a3a747d87c873e5a727c
call_targets: 0x367ba7d034abf0b97bccdf07fd95217410c9dbe8
target_varies: no
classification: constant_target
validation_json
{
    "sink": "CALL",
    "errors": 0,
    "status": "sink_reached",
    "attempts": 1,
    "trace_id": "0x09febf62874f57fb20e29e0f289c69e4bb05508ae453a3a747d87c873e5a727c",
    "confirmed": false,
    "trace_mode": "callTracer",
    "call_targets": [
        "0x367ba7d034abf0b97bccdf07fd95217410c9dbe8"
    ],
    "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": "0x251c1aa3",
            "selector": "0x251c1aa3",
            "calldata_variants": [
                "0x251c1aa3",
                "0x251c1aa30000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0x3ccfd60b",
            "selector": "0x3ccfd60b",
            "calldata_variants": [
                "0x3ccfd60b",
                "0x3ccfd60b0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0x8380edb7",
            "selector": "0x8380edb7",
            "calldata_variants": [
                "0x8380edb7",
                "0x8380edb70000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0x8da5cb5b",
            "selector": "0x8da5cb5b",
            "calldata_variants": [
                "0x8da5cb5b",
                "0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xa1db9782",
            "selector": "0xa1db9782",
            "calldata_variants": [
                "0xa1db9782",
                "0xa1db97820000000000000000000000000000000000000000000000000000000000000000"
            ]
        }
    ]
}
evidence_json
{
    "examples": [
        {
            "pc": 584,
            "opcode": "CALL",
            "returndata_checked": null,
            "value_expression_category": "computed",
            "target_expression_category": "computed"
        },
        {
            "pc": 1098,
            "opcode": "CALL",
            "returndata_checked": null,
            "value_expression_category": "computed",
            "target_expression_category": "computed"
        }
    ],
    "eth_value_calls": 2,
    "guards_detected": [
        {
            "pc": 416,
            "type": "msg_sender_eq_const",
            "value": "0xffffffffffffffffffffffffffffffffffffffff"
        },
        {
            "pc": 786,
            "type": "msg_sender_eq_const",
            "value": "0xffffffffffffffffffffffffffffffffffffffff"
        }
    ]
}