019b3836-31ad-7277-b6aa-d13e6daa98f7
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 |
|---|---|---|---|---|
| 2825 | artifact.fetch | complete | 1 / 3 | 3 months ago |
| 2826 | tool.cast_disasm | complete | 1 / 3 | 3 months ago |
| 46140 | analysis.bundle | complete | 1 / 3 | 1 week ago |
| 46141 | capability.graph | complete | 1 / 3 | 1 week ago |
| 46142 | detector.run | complete | 1 / 3 | 1 week ago |
| 46143 | validation.fork | complete | 1 / 3 | 1 week ago |
| 113256 | report.consolidate | complete | 1 / 6 | 1 week ago |
No slither job recorded yet.
{"no_findings":false,"summary":"Bytecode shows an owner-gated `SELFDESTRUCT`/fund-sweep path and a public value-bearing low-level `CALL` whose success is ignored. Selector inference is best-effort, but the control flow and sink reachability are clear from `BYTECODE_BUNDLE.json`. On Ethereum mainnet, `SELFDESTRUCT` still transfers ETH to the beneficiary even when code removal is limited by EIP-6780.","findings":[{"severity":"medium","category":"access_control","title":"Privileged fund sweep via owner-gated SELFDESTRUCT","exploit_scenario":"The function at selector `0xa7f43779` checks `CALLER` against the lower 160 bits of storage slot `0x0` and then executes `SELFDESTRUCT` to that same address. If users expect the contract balance to be used only by the public payout path, the slot-0 owner can bypass that expectation and sweep all ETH to themselves at any time.","recommendation":"Remove the runtime `SELFDESTRUCT` path if trustless custody is intended. If an emergency escape hatch is required, gate it behind stronger governance such as a timelock/multisig and document the trust assumption explicitly.","evidence":"At `pc:0x6f`/`pc:0x85` the contract `SLOAD`s slot `0x0`, masks it to 160 bits, compares it to `CALLER` (`pc:0x70`-`pc:0x7e`), and on success executes `SELFDESTRUCT` with the masked slot-0 address at `pc:0x8f`. Runtime has no `SSTORE`, so this privileged beneficiary appears immutable post-deploy. Under current mainnet semantics, this still transfers the full ETH balance to the beneficiary even if code is not deleted.","locations":["selector:0xa7f43779","pc:0x6f","pc:0x8f"]},{"severity":"low","category":"other","title":"Unchecked stipend-style ETH transfer can silently fail and block the intended payout path","exploit_scenario":"The public function at selector `0x4ddd108a` reaches a value-bearing `CALL` to the slot-1 address, and the return value is discarded. If that recipient is a contract with a reverting or gas-hungry `receive`/`fallback`, every payout attempt can fail silently. Callers get no enforced success signal, and the intended beneficiary may never receive funds through the normal path.","recommendation":"Check the low-level `CALL` result and handle failure explicitly. Prefer a pull-withdrawal pattern over stipend-based transfers when the recipient might be a contract.","evidence":"`pc:0x62` is the only `CALL` sink. The surrounding stack setup is consistent with a fixed-value ETH transfer to the masked slot-1 address, and the `CALL` result is ignored via `POP`s at `pc:0x63`-`pc:0x67`. This gas/value inference is bytecode-derived and therefore somewhat uncertain, but it matches the artifact's validated 'ETH value transfer possible' finding and the absence of any returndata checks.","locations":["selector:0x4ddd108a","pc:0x62","pc:0x63"]}]}
OpenAI Codex v0.118.0 (research preview)
--------
workdir: /tmp/codex-eitqo2jg
model: gpt-5.4
provider: openai
approval: never
sandbox: read-only
reasoning effort: high
reasoning summaries: none
session id: 019d5bb2-b037-7802-93cc-c77a0c42283c
--------
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.
warning: Codex could not find system bubblewrap on PATH. Please install bubblewrap with your package manager. Codex will use the vendored bubblewrap in the meantime.
exec
/bin/bash -lc 'rg --files' in /tmp/codex-eitqo2jg
succeeded in 0ms:
codex-output-schema.json
BYTECODE_BUNDLE.json
exec
/bin/bash -lc pwd in /tmp/codex-eitqo2jg
succeeded in 0ms:
/tmp/codex-eitqo2jg
exec
/bin/bash -lc "sed -n '1,260p' BYTECODE_BUNDLE.json" in /tmp/codex-eitqo2jg
succeeded in 0ms:
{
"analysis_artifact": {
"address": "0x68ec09892d6b207bad8394bfe3572010c0c9dff9",
"artifact_hash": "0x7b69366ff660d730f56d1edb71609823e75a06b7822dfed36eaf56dd53065cf9",
"artifact_json": {
"auth": {
"guards": []
},
"basic_blocks": [
{
"end_pc": 23,
"hash": "0x0c2a9a7f8741fe69ba9c55e53bdee42f966ccf396e0bb8b8cf05818f99578f94",
"opcodes": [
"PUSH1",
"PUSH1",
"MSTORE",
"PUSH1",
"PUSH1",
"EXP",
"PUSH1",
"CALLDATALOAD",
"DIV",
"PUSH4",
"OP_81",
"EQ",
"PUSH1",
"JUMPI"
],
"start_pc": 0
},
{
"end_pc": 33,
"hash": "0xc0e68c8c6776ae9c695b6128978cfb7ca817fcb9e693a8d875b3e86ff6fe3f92",
"opcodes": [
"OP_80",
"PUSH4",
"EQ",
"PUSH1",
"JUMPI"
],
"start_pc": 24
},
{
"end_pc": 35,
"hash": "0xd992302ef73b1098f69c9c04a34424995e3f29a3c7f224d984cff0e85dbd9591",
"opcodes": [
"JUMPDEST",
"STOP"
],
"start_pc": 34
},
{
"end_pc": 66,
"hash": "0xd5e1c2dec6633b15cbad664290d702d032bc73cff34c4c7b75479e1384c898bf",
"opcodes": [
"JUMPDEST",
"PUSH1",
"PUSH1",
"SLOAD",
"PUSH7",
"PUSH1",
"PUSH1",
"PUSH1",
"EXP",
"SUB",
"OP_91",
"OP_90",
"OP_91",
"AND",
"BALANCE",
"LT",
"PUSH1",
"JUMPI"
],
"start_pc": 36
},
{
"end_pc": 103,
"hash": "0xb816588f0cb99db1a63de91796ef8ec990012c251d5f30ec2d7ccc3e341556f1",
"opcodes": [
"PUSH1",
"SLOAD",
"PUSH1",
"PUSH1",
"PUSH1",
"EXP",
"SUB",
"AND",
"PUSH1",
"PUSH7",
"PUSH1",
"OP_82",
"OP_81",
"OP_81",
"OP_81",
"OP_85",
"OP_88",
"OP_83",
"CALL",
"POP",
"POP",
"POP",
"POP",
"POP"
],
"start_pc": 67
},
{
"end_pc": 105,
"hash": "0xf202c73297728ba8cb50636fbad74fd6d18375a8a97d3e2bc56502b475a33624",
"opcodes": [
"JUMPDEST",
"JUMP"
],
"start_pc": 104
},
{
"end_pc": 130,
"hash": "0xcdd4cb7094d2c00dcf7bf9c3f7d64087b13bbb86be22221b73be3279720327ad",
"opcodes": [
"JUMPDEST",
"PUSH1",
"PUSH1",
"SLOAD",
"CALLER",
"PUSH1",
"PUSH1",
"PUSH1",
"EXP",
"SUB",
"OP_90",
"OP_81",
"AND",
"OP_91",
"AND",
"EQ",
"ISZERO",
"PUSH1",
"JUMPI"
],
"start_pc": 106
},
{
"end_pc": 143,
"hash": "0xffa0a8d549b9b077c447800d5b3c6763bcf4a2fce075ead83c908dd998dbdf24",
"opcodes": [
"PUSH1",
"SLOAD",
"PUSH1",
"PUSH1",
"PUSH1",
"EXP",
"SUB",
"AND",
"SELFDESTRUCT"
],
"start_pc": 131
}
],
"callsites": [
{
"opcode": "CALL",
"pc": 98,
"returndata_checked": null,
"target_expression_category": "computed",
"value_expression_category": "computed"
}
],
"cfg_edges": [
{
"from": "bb:0",
"to": "bb:36",
"type": "control_flow"
},
{
"from": "bb:0",
"to": "bb:24",
"type": "control_flow_fallthrough"
},
{
"from": "bb:24",
"to": "bb:106",
"type": "control_flow"
},
{
"from": "bb:24",
"to": "bb:34",
"type": "control_flow_fallthrough"
},
{
"from": "bb:36",
"to": "bb:104",
"type": "control_flow"
},
{
"from": "bb:36",
"to": "bb:67",
"type": "control_flow_fallthrough"
},
{
"from": "bb:67",
"to": "bb:104",
"type": "control_flow_fallthrough"
},
{
"from": "bb:106",
"to": "bb:104",
"type": "control_flow"
},
{
"from": "bb:106",
"to": "bb:131",
"type": "control_flow_fallthrough"
}
],
"cfg_hash": "0x99443d47a40d859dddea2312945ed900a40963edb6ef4a446b1d9261647a470d",
"dispatcher_type": "selector_jump_table",
"function_entries": [
{
"entry_pc": null,
"selector": "0x4ddd108a"
},
{
"entry_pc": null,
"selector": "0xa7f43779"
}
],
"functions": [
{
"auth": {
"guards": []
},
"entry_pc": null,
"selector": "0x4ddd108a",
"sinks": {
"call": 1,
"delegatecall": 0,
"selfdestruct": 1,
"staticcall": 0
},
"storage": {
"reads": 4,
"slots": [
{
"op": "SLOAD",
"pc": 41,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
},
{
"op": "SLOAD",
"pc": 69,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
{
"op": "SLOAD",
"pc": 111,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"op": "SLOAD",
exec
/bin/bash -lc "sed -n '261,520p' BYTECODE_BUNDLE.json" in /tmp/codex-eitqo2jg
succeeded in 0ms:
"pc": 133,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
],
"writes": 0
}
},
{
"auth": {
"guards": []
},
"entry_pc": null,
"selector": "0xa7f43779",
"sinks": {
"call": 1,
"delegatecall": 0,
"selfdestruct": 1,
"staticcall": 0
},
"storage": {
"reads": 4,
"slots": [
{
"op": "SLOAD",
"pc": 41,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
},
{
"op": "SLOAD",
"pc": 69,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
{
"op": "SLOAD",
"pc": 111,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"op": "SLOAD",
"pc": 133,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
],
"writes": 0
}
}
],
"selectors": [
"0x4ddd108a",
"0xa7f43779"
],
"sinks": {
"call": 1,
"create": 0,
"create2": 0,
"delegatecall": 0,
"selfdestruct": 1,
"staticcall": 0,
"upgrade_slot_write_suspected": false
},
"storage": {
"keccak_count": 0,
"reads": 4,
"slots": [
{
"op": "SLOAD",
"pc": 41,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
},
{
"op": "SLOAD",
"pc": 69,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
{
"op": "SLOAD",
"pc": 111,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"op": "SLOAD",
"pc": 133,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
],
"writes": 0
},
"version": "analysis_artifact_v1"
},
"block_number": null,
"chain_id": 1,
"codehash": "0x2d18960ca0a1942ab259c7ae5e59af992e46ac7e6bd4dfa8a85827ff0a188e19",
"created_at": "2026-04-04T19:54:53.000000Z",
"id": 2192,
"updated_at": "2026-04-04T19:54:53.000000Z",
"version": "analysis_artifact_v1"
},
"analysis_run": {
"address": "0x68ec09892d6b207bad8394bfe3572010c0c9dff9",
"block_number": null,
"chain_id": 1,
"child_links": [],
"created_at": "2025-12-19T20:03:54.000000Z",
"id": "019b3836-31ad-7277-b6aa-d13e6daa98f7",
"parent_links": [],
"status": "running",
"updated_at": "2026-04-04T19:54:53.000000Z"
},
"artifact": {
"codehash": "0x2d18960ca0a1942ab259c7ae5e59af992e46ac7e6bd4dfa8a85827ff0a188e19",
"compiler_json": {
"etherscan": {
"skipped": true
}
},
"implementation_address": null,
"is_proxy": false,
"runtime_bytecode": {
"full": "0x606060405260e060020a60003504634ddd108a81146024578063a7f4377914606a575b005b60226002546638d7ea4c680000600160a060020a03919091163110606857600154600160a060020a03166000661c6bf526340000606082818181858883f150505050505b565b602260005433600160a060020a0390811691161415606857600054600160a060020a0316ff",
"head": null,
"length": 290,
"tail": null,
"truncated": false
},
"verified_source": false
},
"capability_graph": {
"address": "0x68ec09892d6b207bad8394bfe3572010c0c9dff9",
"block_number": null,
"chain_id": 1,
"codehash": "0x2d18960ca0a1942ab259c7ae5e59af992e46ac7e6bd4dfa8a85827ff0a188e19",
"created_at": "2026-04-04T19:54:53.000000Z",
"graph_hash": "0x67b2b4afad889e1e67b5ed52655a367d4ca69f2d488a6a275fc996b06bba845f",
"graph_json": {
"edges": [
{
"from": "bb:0",
"to": "bb:36",
"type": "control_flow"
},
{
"from": "bb:0",
"to": "bb:24",
"type": "control_flow_fallthrough"
},
{
"from": "bb:24",
"to": "bb:106",
"type": "control_flow"
},
{
"from": "bb:24",
"to": "bb:34",
"type": "control_flow_fallthrough"
},
{
"from": "bb:36",
"to": "bb:104",
"type": "control_flow"
},
{
"from": "bb:36",
"to": "bb:67",
"type": "control_flow_fallthrough"
},
{
"from": "bb:67",
"to": "bb:104",
"type": "control_flow_fallthrough"
},
{
"from": "bb:106",
"to": "bb:104",
"type": "control_flow"
},
{
"from": "bb:106",
"to": "bb:131",
"type": "control_flow_fallthrough"
},
{
"from": "bb:67",
"to": "call:98",
"type": "contains"
},
{
"from": "call:98",
"to": "sink:call",
"type": "capability"
}
],
"nodes": [
{
"end_pc": 23,
"hash": "0x0c2a9a7f8741fe69ba9c55e53bdee42f966ccf396e0bb8b8cf05818f99578f94",
"id": "bb:0",
"start_pc": 0,
"type": "basic_block"
},
{
"end_pc": 33,
"hash": "0xc0e68c8c6776ae9c695b6128978cfb7ca817fcb9e693a8d875b3e86ff6fe3f92",
"id": "bb:24",
"start_pc": 24,
"type": "basic_block"
},
{
"end_pc": 35,
"hash": "0xd992302ef73b1098f69c9c04a34424995e3f29a3c7f224d984cff0e85dbd9591",
"id": "bb:34",
"start_pc": 34,
"type": "basic_block"
},
{
"end_pc": 66,
"hash": "0xd5e1c2dec6633b15cbad664290d702d032bc73cff34c4c7b75479e1384c898bf",
"id": "bb:36",
"start_pc": 36,
"type": "basic_block"
},
{
"end_pc": 103,
"hash": "0xb816588f0cb99db1a63de91796ef8ec990012c251d5f30ec2d7ccc3e341556f1",
"id": "bb:67",
"start_pc": 67,
"type": "basic_block"
},
{
"end_pc": 105,
"hash": "0xf202c73297728ba8cb50636fbad74fd6d18375a8a97d3e2bc56502b475a33624",
"id": "bb:104",
"start_pc": 104,
"type": "basic_block"
},
{
"end_pc": 130,
"hash": "0xcdd4cb7094d2c00dcf7bf9c3f7d64087b13bbb86be22221b73be3279720327ad",
"id": "bb:106",
"start_pc": 106,
"type": "basic_block"
},
{
"end_pc": 143,
"hash": "0xffa0a8d549b9b077c447800d5b3c6763bcf4a2fce075ead83c908dd998dbdf24",
"id": "bb:131",
"start_pc": 131,
"type": "basic_block"
},
{
"id": "call:98",
"opcode": "CALL",
"pc": 98,
"type": "callsite"
},
{
"id": "sink:call",
"type": "sink"
},
{
"entry_pc": null,
exec
/bin/bash -lc "sed -n '521,920p' BYTECODE_BUNDLE.json" in /tmp/codex-eitqo2jg
succeeded in 0ms:
"id": "fn:0x4ddd108a",
"selector": "0x4ddd108a",
"type": "function"
},
{
"entry_pc": null,
"id": "fn:0xa7f43779",
"selector": "0xa7f43779",
"type": "function"
}
],
"version": "capability_graph_v1"
},
"id": 2192,
"updated_at": "2026-04-04T19:54:53.000000Z",
"version": "capability_graph_v1"
},
"detector_findings": [
{
"confidence": 60,
"evidence_json": {
"call_count": 1,
"examples": [
{
"opcode": "CALL",
"pc": 98,
"returndata_checked": null,
"target_expression_category": "computed",
"value_expression_category": "computed"
}
],
"guards_detected": [],
"untrusted_call_count": 1
},
"normalized_json": {
"sink": "CALL"
},
"severity": "high",
"title": "Untrusted CALL target/value reachable",
"validated": true,
"validation_json": {
"attempts": 1,
"call_targets": [
"0x68ec09892d6b207bad8394bfe3572010c0c9dff9",
"0xdc0e1e26578f8337f9a4da87deebd978dc650017"
],
"classification": "target_varies",
"confirmed": true,
"errors": 0,
"matched_probe": null,
"sink": "CALL",
"status": "confirmed",
"target_varies": true,
"trace_id": "0xfbf9f3eacf5473d0cc1e0f4bfd52b26fca6d892a6cef932dba58e2a37c8009f0",
"trace_mode": "callTracer"
}
},
{
"confidence": 55,
"evidence_json": {
"eth_value_calls": 1,
"examples": [
{
"opcode": "CALL",
"pc": 98,
"returndata_checked": null,
"target_expression_category": "computed",
"value_expression_category": "computed"
}
],
"guards_detected": []
},
"normalized_json": {
"sink": "CALL",
"value": "nonzero"
},
"severity": "high",
"title": "ETH value transfer possible",
"validated": true,
"validation_json": {
"attempts": 1,
"call_targets": [
"0x68ec09892d6b207bad8394bfe3572010c0c9dff9",
"0xdc0e1e26578f8337f9a4da87deebd978dc650017"
],
"classification": "target_varies",
"confirmed": true,
"errors": 0,
"matched_probe": null,
"sink": "CALL",
"status": "confirmed",
"target_varies": true,
"trace_id": "0xfbf9f3eacf5473d0cc1e0f4bfd52b26fca6d892a6cef932dba58e2a37c8009f0",
"trace_mode": "callTracer"
}
},
{
"confidence": 65,
"evidence_json": {
"guards_detected": [],
"selfdestruct_count": 1
},
"normalized_json": {
"sink": "SELFDESTRUCT"
},
"severity": "high",
"title": "SELFDESTRUCT reachable",
"validated": false,
"validation_json": {
"attempts": 4,
"call_targets": null,
"classification": "no_sink",
"confirmed": false,
"errors": 0,
"matched_probe": null,
"sink": "SELFDESTRUCT",
"status": "unknown",
"target_varies": null,
"trace_id": "0xa6b8df0043cd493a604113021252490dbde199e836634c175b08221581569b7a",
"trace_mode": "structLogs"
}
}
],
"heuristics_summary": {
"create2_count": 0,
"delegatecall_count": 0,
"flags": [
"selfdestruct_present"
],
"selfdestruct_count": 1
}
}
exec
/bin/bash -lc "node - <<'NODE'
const hex='606060405260e060020a60003504634ddd108a81146024578063a7f4377914606a575b005b60226002546638d7ea4c680000600160a060020a03919091163110606857600154600160a060020a03166000661c6bf526340000606082818181858883f150505050505b565b602260005433600160a060020a0390811691161415606857600054600160a060020a0316ff';
const buf=Buffer.from(hex,'hex');
for(let i=0;i<buf.length;){
const op=buf[i];
if(op>=0x60&&op<=0x7f){const n=op-0x5f; console.log(i.toString(16).padStart(4,'0'), 'PUSH'+n, '0x'+buf.slice(i+1,i+1+n).toString('hex')); i+=1+n;}
else {
const map={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x0a:'EXP',0x10:'LT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x31:'BALANCE',0x33:'CALLER',0x35:'CALLDATALOAD',0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x54:'SLOAD',0x56:'JUMP',0x57:'JUMPI',0x5b:'JUMPDEST',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x85:'DUP6',0x88:'DUP9',0x90:'SWAP1',0x91:'SWAP2',0xf1:'CALL',0xff:'SELFDESTRUCT'};
console.log(i.toString(16).padStart(4,'0'), map[op]||('OP_'+op.toString(16)));
i++;
}
}
NODE" in /tmp/codex-eitqo2jg
succeeded in 0ms:
0000 PUSH1 0x60
0002 PUSH1 0x40
0004 MSTORE
0005 PUSH1 0xe0
0007 PUSH1 0x02
0009 EXP
000a PUSH1 0x00
000c CALLDATALOAD
000d DIV
000e PUSH4 0x4ddd108a
0013 DUP2
0014 EQ
0015 PUSH1 0x24
0017 JUMPI
0018 OP_80
0019 PUSH4 0xa7f43779
001e EQ
001f PUSH1 0x6a
0021 JUMPI
0022 JUMPDEST
0023 STOP
0024 JUMPDEST
0025 PUSH1 0x22
0027 PUSH1 0x02
0029 SLOAD
002a PUSH7 0x38d7ea4c680000
0032 PUSH1 0x01
0034 PUSH1 0xa0
0036 PUSH1 0x02
0038 EXP
0039 SUB
003a SWAP2
003b SWAP1
003c SWAP2
003d AND
003e BALANCE
003f LT
0040 PUSH1 0x68
0042 JUMPI
0043 PUSH1 0x01
0045 SLOAD
0046 PUSH1 0x01
0048 PUSH1 0xa0
004a PUSH1 0x02
004c EXP
004d SUB
004e AND
004f PUSH1 0x00
0051 PUSH7 0x1c6bf526340000
0059 PUSH1 0x60
005b DUP3
005c DUP2
005d DUP2
005e DUP2
005f DUP6
0060 DUP9
0061 DUP4
0062 CALL
0063 POP
0064 POP
0065 POP
0066 POP
0067 POP
0068 JUMPDEST
0069 JUMP
006a JUMPDEST
006b PUSH1 0x22
006d PUSH1 0x00
006f SLOAD
0070 CALLER
0071 PUSH1 0x01
0073 PUSH1 0xa0
0075 PUSH1 0x02
0077 EXP
0078 SUB
0079 SWAP1
007a DUP2
007b AND
007c SWAP2
007d AND
007e EQ
007f ISZERO
0080 PUSH1 0x68
0082 JUMPI
0083 PUSH1 0x00
0085 SLOAD
0086 PUSH1 0x01
0088 PUSH1 0xa0
008a PUSH1 0x02
008c EXP
008d SUB
008e AND
008f SELFDESTRUCT
exec
/bin/bash -lc "node - <<'NODE'
let st=['sel'];
function push(x){st.push(x);}
function sload(){let a=st.pop();st.push("'`sload(${a})`)}
function exp(){let a=st.pop(),b=st.pop();st.push(`(${b}**${a})`)}
function sub(){let a=st.pop(),b=st.pop();st.push(`(${b}-${a})`)}
function and(){let a=st.pop(),b=st.pop();st.push(`(${b}&${a})`)}
function balance(){let a=st.pop();st.push(`balance(${a})`)}
function lt(){let a=st.pop(),b=st.pop();st.push(`(${b}<${a})`)}
function swap(n){let i=st.length-1, j=st.length-1-n; [st[i],st[j]]=[st[j],st[i]]}
function dup(n){st.push(st[st.length-n])}
function pop(){st.pop()}
function log(op){console.log(op, JSON.stringify(st))}
push('"'ret');push('2');sload();push('constA');push('1');push('a0');push('2');exp();sub();swap(2);swap(1);swap(2);and();push('this');balance();lt();log('after lt');
// assume jumphi consumed cond and dest; if false continues with current stack
push('1');sload();push('1');push('a0');push('2');exp();sub();and();push('0');push('constB');push('0x60');dup(3);dup(2);dup(2);dup(2);dup(6);dup(9);dup(4);log('before call');
NODE" in /tmp/codex-eitqo2jg
succeeded in 0ms:
after lt ["sel","ret","constA","((sload(2)&(1-(a0**2)))<balance(this))"]
before call ["sel","ret","constA","((sload(2)&(1-(a0**2)))<balance(this))","(sload(1)&(1-(a0**2)))","0","constB","0x60","0","0x60","0","0x60","constB","(sload(1)&(1-(a0**2)))","0"]
exec
/bin/bash -lc "node - <<'NODE'
console.log('A', BigInt('0x38d7ea4c680000').toString())
console.log('B', BigInt('0x1c6bf526340000').toString())
NODE" in /tmp/codex-eitqo2jg
succeeded in 0ms:
A 16000000000000000
B 8000000000000000
codex
{"no_findings":false,"summary":"Bytecode shows an owner-gated `SELFDESTRUCT`/fund-sweep path and a public value-bearing low-level `CALL` whose success is ignored. Selector inference is best-effort, but the control flow and sink reachability are clear from `BYTECODE_BUNDLE.json`. On Ethereum mainnet, `SELFDESTRUCT` still transfers ETH to the beneficiary even when code removal is limited by EIP-6780.","findings":[{"severity":"medium","category":"access_control","title":"Privileged fund sweep via owner-gated SELFDESTRUCT","exploit_scenario":"The function at selector `0xa7f43779` checks `CALLER` against the lower 160 bits of storage slot `0x0` and then executes `SELFDESTRUCT` to that same address. If users expect the contract balance to be used only by the public payout path, the slot-0 owner can bypass that expectation and sweep all ETH to themselves at any time.","recommendation":"Remove the runtime `SELFDESTRUCT` path if trustless custody is intended. If an emergency escape hatch is required, gate it behind stronger governance such as a timelock/multisig and document the trust assumption explicitly.","evidence":"At `pc:0x6f`/`pc:0x85` the contract `SLOAD`s slot `0x0`, masks it to 160 bits, compares it to `CALLER` (`pc:0x70`-`pc:0x7e`), and on success executes `SELFDESTRUCT` with the masked slot-0 address at `pc:0x8f`. Runtime has no `SSTORE`, so this privileged beneficiary appears immutable post-deploy. Under current mainnet semantics, this still transfers the full ETH balance to the beneficiary even if code is not deleted.","locations":["selector:0xa7f43779","pc:0x6f","pc:0x8f"]},{"severity":"low","category":"other","title":"Unchecked stipend-style ETH transfer can silently fail and block the intended payout path","exploit_scenario":"The public function at selector `0x4ddd108a` reaches a value-bearing `CALL` to the slot-1 address, and the return value is discarded. If that recipient is a contract with a reverting or gas-hungry `receive`/`fallback`, every payout attempt can fail silently. Callers get no enforced success signal, and the intended beneficiary may never receive funds through the normal path.","recommendation":"Check the low-level `CALL` result and handle failure explicitly. Prefer a pull-withdrawal pattern over stipend-based transfers when the recipient might be a contract.","evidence":"`pc:0x62` is the only `CALL` sink. The surrounding stack setup is consistent with a fixed-value ETH transfer to the masked slot-1 address, and the `CALL` result is ignored via `POP`s at `pc:0x63`-`pc:0x67`. This gas/value inference is bytecode-derived and therefore somewhat uncertain, but it matches the artifact's validated 'ETH value transfer possible' finding and the absence of any returndata checks.","locations":["selector:0x4ddd108a","pc:0x62","pc:0x63"]}]}
tokens used
41,956
{
"codex": {
"ran_at": "2026-04-05T03:35:03.823440+00:00",
"returncode": 0
},
"project": {
"mode": "bytecode",
"bytecode_length": 290,
"bytecode_truncated": false,
"capability_graph_present": true,
"analysis_artifact_present": true
},
"summary": "Bytecode shows an owner-gated `SELFDESTRUCT`/fund-sweep path and a public value-bearing low-level `CALL` whose success is ignored. Selector inference is best-effort, but the control flow and sink reachability are clear from `BYTECODE_BUNDLE.json`. On Ethereum mainnet, `SELFDESTRUCT` still transfers ETH to the beneficiary even when code removal is limited by EIP-6780.",
"raw_final": {
"summary": "Bytecode shows an owner-gated `SELFDESTRUCT`/fund-sweep path and a public value-bearing low-level `CALL` whose success is ignored. Selector inference is best-effort, but the control flow and sink reachability are clear from `BYTECODE_BUNDLE.json`. On Ethereum mainnet, `SELFDESTRUCT` still transfers ETH to the beneficiary even when code removal is limited by EIP-6780.",
"findings": [
{
"title": "Privileged fund sweep via owner-gated SELFDESTRUCT",
"category": "access_control",
"evidence": "At `pc:0x6f`/`pc:0x85` the contract `SLOAD`s slot `0x0`, masks it to 160 bits, compares it to `CALLER` (`pc:0x70`-`pc:0x7e`), and on success executes `SELFDESTRUCT` with the masked slot-0 address at `pc:0x8f`. Runtime has no `SSTORE`, so this privileged beneficiary appears immutable post-deploy. Under current mainnet semantics, this still transfers the full ETH balance to the beneficiary even if code is not deleted.",
"severity": "medium",
"locations": [
"selector:0xa7f43779",
"pc:0x6f",
"pc:0x8f"
],
"recommendation": "Remove the runtime `SELFDESTRUCT` path if trustless custody is intended. If an emergency escape hatch is required, gate it behind stronger governance such as a timelock/multisig and document the trust assumption explicitly.",
"exploit_scenario": "The function at selector `0xa7f43779` checks `CALLER` against the lower 160 bits of storage slot `0x0` and then executes `SELFDESTRUCT` to that same address. If users expect the contract balance to be used only by the public payout path, the slot-0 owner can bypass that expectation and sweep all ETH to themselves at any time."
},
{
"title": "Unchecked stipend-style ETH transfer can silently fail and block the intended payout path",
"category": "other",
"evidence": "`pc:0x62` is the only `CALL` sink. The surrounding stack setup is consistent with a fixed-value ETH transfer to the masked slot-1 address, and the `CALL` result is ignored via `POP`s at `pc:0x63`-`pc:0x67`. This gas/value inference is bytecode-derived and therefore somewhat uncertain, but it matches the artifact's validated 'ETH value transfer possible' finding and the absence of any returndata checks.",
"severity": "low",
"locations": [
"selector:0x4ddd108a",
"pc:0x62",
"pc:0x63"
],
"recommendation": "Check the low-level `CALL` result and handle failure explicitly. Prefer a pull-withdrawal pattern over stipend-based transfers when the recipient might be a contract.",
"exploit_scenario": "The public function at selector `0x4ddd108a` reaches a value-bearing `CALL` to the slot-1 address, and the return value is discarded. If that recipient is a contract with a reverting or gas-hungry `receive`/`fallback`, every payout attempt can fail silently. Callers get no enforced success signal, and the intended beneficiary may never receive funds through the normal path."
}
],
"no_findings": false
},
"no_findings": false,
"schema_version": 1
}
00000000: PUSH1 0x60 00000002: PUSH1 0x40 00000004: MSTORE 00000005: PUSH1 0xe0 00000007: PUSH1 0x02 00000009: EXP 0000000a: PUSH1 0x00 0000000c: CALLDATALOAD 0000000d: DIV 0000000e: PUSH4 0x4ddd108a 00000013: DUP2 00000014: EQ 00000015: PUSH1 0x24 00000017: JUMPI 00000018: DUP1 00000019: PUSH4 0xa7f43779 0000001e: EQ 0000001f: PUSH1 0x6a 00000021: JUMPI 00000022: JUMPDEST 00000023: STOP 00000024: JUMPDEST 00000025: PUSH1 0x22 00000027: PUSH1 0x02 00000029: SLOAD 0000002a: PUSH7 0x38d7ea4c680000 00000032: PUSH1 0x01 00000034: PUSH1 0xa0 00000036: PUSH1 0x02 00000038: EXP 00000039: SUB 0000003a: SWAP2 0000003b: SWAP1 0000003c: SWAP2 0000003d: AND 0000003e: BALANCE 0000003f: LT 00000040: PUSH1 0x68 00000042: JUMPI 00000043: PUSH1 0x01 00000045: SLOAD 00000046: PUSH1 0x01 00000048: PUSH1 0xa0 0000004a: PUSH1 0x02 0000004c: EXP 0000004d: SUB 0000004e: AND 0000004f: PUSH1 0x00 00000051: PUSH7 0x1c6bf526340000 00000059: PUSH1 0x60 0000005b: DUP3 0000005c: DUP2 0000005d: DUP2 0000005e: DUP2 0000005f: DUP6 00000060: DUP9 00000061: DUP4 00000062: CALL 00000063: POP 00000064: POP 00000065: POP 00000066: POP 00000067: POP 00000068: JUMPDEST 00000069: JUMP 0000006a: JUMPDEST 0000006b: PUSH1 0x22 0000006d: PUSH1 0x00 0000006f: SLOAD 00000070: CALLER 00000071: PUSH1 0x01 00000073: PUSH1 0xa0 00000075: PUSH1 0x02 00000077: EXP 00000078: SUB 00000079: SWAP1 0000007a: DUP2 0000007b: AND 0000007c: SWAP2 0000007d: AND 0000007e: EQ 0000007f: ISZERO 00000080: PUSH1 0x68 00000082: JUMPI 00000083: PUSH1 0x00 00000085: SLOAD 00000086: PUSH1 0x01 00000088: PUSH1 0xa0 0000008a: PUSH1 0x02 0000008c: EXP 0000008d: SUB 0000008e: AND 0000008f: SELFDESTRUCT
Warning: This is a nightly build of Foundry. It is recommended to use the latest stable version. To mute this warning set `FOUNDRY_DISABLE_NIGHTLY_WARNING` in your environment.
| Severity | Category | Tool | Title | Confidence | Validated | Confirmed | Details |
|---|---|---|---|---|---|---|---|
| high | other | detector | Untrusted CALL target/value reachable | 60 | yes | yes |
viewtrace_id: 0xfbf9f3eacf5473d0cc1e0f4bfd52b26fca6d892a6cef932dba58e2a37c8009f0
call_targets:
0x68ec09892d6b207bad8394bfe3572010c0c9dff9, 0xdc0e1e26578f8337f9a4da87deebd978dc650017
target_varies:
yes
classification:
target_varies
validation_json{
"sink": "CALL",
"errors": 0,
"status": "confirmed",
"attempts": 1,
"trace_id": "0xfbf9f3eacf5473d0cc1e0f4bfd52b26fca6d892a6cef932dba58e2a37c8009f0",
"confirmed": true,
"trace_mode": "callTracer",
"call_targets": [
"0x68ec09892d6b207bad8394bfe3572010c0c9dff9",
"0xdc0e1e26578f8337f9a4da87deebd978dc650017"
],
"matched_probe": null,
"target_varies": true,
"classification": "target_varies"
}
witness_json{
"notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
"constraints": [],
"entrypoints": [
{
"calldata": "0x4ddd108a",
"selector": "0x4ddd108a",
"calldata_variants": [
"0x4ddd108a",
"0x4ddd108a0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xa7f43779",
"selector": "0xa7f43779",
"calldata_variants": [
"0xa7f43779",
"0xa7f437790000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 98,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
}
],
"call_count": 1,
"guards_detected": [],
"untrusted_call_count": 1
}
|
| high | other | detector | ETH value transfer possible | 55 | yes | yes |
viewtrace_id: 0xfbf9f3eacf5473d0cc1e0f4bfd52b26fca6d892a6cef932dba58e2a37c8009f0
call_targets:
0x68ec09892d6b207bad8394bfe3572010c0c9dff9, 0xdc0e1e26578f8337f9a4da87deebd978dc650017
target_varies:
yes
classification:
target_varies
validation_json{
"sink": "CALL",
"errors": 0,
"status": "confirmed",
"attempts": 1,
"trace_id": "0xfbf9f3eacf5473d0cc1e0f4bfd52b26fca6d892a6cef932dba58e2a37c8009f0",
"confirmed": true,
"trace_mode": "callTracer",
"call_targets": [
"0x68ec09892d6b207bad8394bfe3572010c0c9dff9",
"0xdc0e1e26578f8337f9a4da87deebd978dc650017"
],
"matched_probe": null,
"target_varies": true,
"classification": "target_varies"
}
witness_json{
"notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
"constraints": [],
"entrypoints": [
{
"calldata": "0x4ddd108a",
"selector": "0x4ddd108a",
"calldata_variants": [
"0x4ddd108a",
"0x4ddd108a0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xa7f43779",
"selector": "0xa7f43779",
"calldata_variants": [
"0xa7f43779",
"0xa7f437790000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 98,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
}
],
"eth_value_calls": 1,
"guards_detected": []
}
|
| high | other | detector | SELFDESTRUCT reachable | 65 | no | no |
viewtrace_id: 0xa6b8df0043cd493a604113021252490dbde199e836634c175b08221581569b7a
validation_json{
"sink": "SELFDESTRUCT",
"errors": 0,
"status": "unknown",
"attempts": 4,
"trace_id": "0xa6b8df0043cd493a604113021252490dbde199e836634c175b08221581569b7a",
"confirmed": false,
"trace_mode": "structLogs",
"call_targets": null,
"matched_probe": null,
"target_varies": null,
"classification": "no_sink"
}
witness_json{
"notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
"constraints": [],
"entrypoints": [
{
"calldata": "0x4ddd108a",
"selector": "0x4ddd108a",
"calldata_variants": [
"0x4ddd108a",
"0x4ddd108a0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xa7f43779",
"selector": "0xa7f43779",
"calldata_variants": [
"0xa7f43779",
"0xa7f437790000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"guards_detected": [],
"selfdestruct_count": 1
}
|
| medium | access_control | codex | Privileged fund sweep via owner-gated SELFDESTRUCT | 75 | no | — |
viewevidence_json{
"evidence": "At `pc:0x6f`/`pc:0x85` the contract `SLOAD`s slot `0x0`, masks it to 160 bits, compares it to `CALLER` (`pc:0x70`-`pc:0x7e`), and on success executes `SELFDESTRUCT` with the masked slot-0 address at `pc:0x8f`. Runtime has no `SSTORE`, so this privileged beneficiary appears immutable post-deploy. Under current mainnet semantics, this still transfers the full ETH balance to the beneficiary even if code is not deleted.",
"locations": [
"selector:0xa7f43779",
"pc:0x6f",
"pc:0x8f"
],
"recommendation": "Remove the runtime `SELFDESTRUCT` path if trustless custody is intended. If an emergency escape hatch is required, gate it behind stronger governance such as a timelock/multisig and document the trust assumption explicitly.",
"exploit_scenario": "The function at selector `0xa7f43779` checks `CALLER` against the lower 160 bits of storage slot `0x0` and then executes `SELFDESTRUCT` to that same address. If users expect the contract balance to be used only by the public payout path, the slot-0 owner can bypass that expectation and sweep all ETH to themselves at any time."
}
|
| low | other | codex | Unchecked stipend-style ETH transfer can silently fail and block the intended payout path | 65 | no | — |
viewevidence_json{
"evidence": "`pc:0x62` is the only `CALL` sink. The surrounding stack setup is consistent with a fixed-value ETH transfer to the masked slot-1 address, and the `CALL` result is ignored via `POP`s at `pc:0x63`-`pc:0x67`. This gas/value inference is bytecode-derived and therefore somewhat uncertain, but it matches the artifact's validated 'ETH value transfer possible' finding and the absence of any returndata checks.",
"locations": [
"selector:0x4ddd108a",
"pc:0x62",
"pc:0x63"
],
"recommendation": "Check the low-level `CALL` result and handle failure explicitly. Prefer a pull-withdrawal pattern over stipend-based transfers when the recipient might be a contract.",
"exploit_scenario": "The public function at selector `0x4ddd108a` reaches a value-bearing `CALL` to the slot-1 address, and the return value is discarded. If that recipient is a contract with a reverting or gas-hungry `receive`/`fallback`, every payout attempt can fail silently. Callers get no enforced success signal, and the intended beneficiary may never receive funds through the normal path."
}
|