# The exploit hiding in dead code: orphan-block DELEGATECALL

> How a computed jump into an orphan basic block hides a DELEGATECALL exploit — and how the Auditing IDE surfaces it.

Vulnerability research

June 15, 2026 · 4 min read

Some of the most dangerous bytecode never appears in the source. It lives in a basic block that looks unreachable — until a computed jump lands on it at runtime. Static source tools don't see it. Here's how BEVM finds it and Janus turns it into a kill chain.

> **Illustrative.** The contract and traces below are a representative, synthetic example used to teach the pattern. The technique — CFG reachability + computed-jump discovery + fork-replay confirmation — is exactly what BEVM, our bytecode-level EVM engine and the analysis core behind what the product calls the Auditing IDE, runs on real targets. **Availability, September 2026:** Janus AI is in development and not yet available — its write-up in step 4 is from our development build.

## Why source-level tools miss it

The EVM has no functions — only `JUMP`, `JUMPI`, and `JUMPDEST`. A Solidity compiler emits a jump table at the top of the contract that dispatches on the 4-byte selector. But jump *targets* can be computed at runtime, and not every reachable `JUMPDEST` corresponds to a public function in the source. When a block holds a powerful opcode — `DELEGATECALL`, `SELFDESTRUCT`, an unguarded `SSTORE` to slot 0 — but appears "orphaned" from the normal dispatcher, a source-only linter has nothing to flag. The bytecode tells a different story.

## Step 1 — X-ray the bytecode

In BEVM you attach by address (or paste bytecode). Within a second you get the disassembly, the resolved selectors, and the control-flow graph. The left rail lists every basic block with a verb and a flag — and the ones we care about are tagged `orphan`:

```
# BEVM · CFG BLOCKS
0x2f2  PROXY   PATCH → JUMPI (46)   SSTORE   orphan / unreached
0x32b  PROXY   TRANSFER → JUMPI (36) CALL     orphan / unreached
0x4a1          OPAQUE → JUMP (12)     DELEGATECALL  orphan / unreached
```

Block `0x4a1` contains a `DELEGATECALL` and is marked `orphan / unreached` — the standard dispatcher never falls through to it. That is precisely the kind of block an attacker hunts for.

## Step 2 — can it actually be reached?

"Unreached by the dispatcher" is not the same as "unreachable." BEVM builds a reachability map and looks for **computed jumps** — a `JUMP` whose destination is taken from calldata, storage, or a prior computation. If some path lets an attacker steer the program counter onto `0x4a1`, the dead code is suddenly very much alive.

```
# attack-graph: who can write the jump target?
selector 0x5ec2dc8d  → writes slot 0x6 (jumpTarget)   ungated
block    0x4a1        ← JUMP [slot 0x6]               DELEGATECALL [slot 0x7]
slot 0x7 (impl) ← writable via selector 0x3d103b6d      ungated
```

Now the shape is clear: two ungated setters let an attacker control both the jump target *and* the `DELEGATECALL` implementation address. Point the jump at `0x4a1`, point the implementation at an attacker contract, and the victim delegate-calls into attacker code with the victim's storage and balance. That is full takeover.

## Step 3 — prove it on a fork

A graph is a hypothesis. The engine's fuzzer takes the attack-graph routes as seeds (orphan-block PCs get priority), and any candidate that moves value is replayed on a pinned mainnet fork. Only a strictly positive, attacker-controlled balance delta is reported:

```
# BEVM · fork replay verdict
chain: setJumpTarget(0x4a1) → setImpl(attacker) → trigger()
  step 1  ok   SSTORE slot 0x6 = 0x4a1
  step 2  ok   SSTORE slot 0x7 = 0xATTACKER
  step 3  ok   DELEGATECALL → attacker.sweep()
  ─────────────────────────────────────────────
  CONFIRMED  attacker_eth_delta = +142.3 ETH   (replayed on fork)
```

## Step 4 — let Janus explain it

**Availability, September 2026.** Janus AI is in development and not yet available — nothing in the product calls it today. The write-up below is from our development build, kept as written. Everything above this step — the CFG, engine-level fuzzing, the fork replay — is available in the workbench; this step is not.

Findings still need to be understood and fixed. Paste the result into Janus and it reasons like an attacker, then writes it up for a human:

> **CRITICAL — Arbitrary DELEGATECALL via computed jump.** Two ungated setters (`0x5ec2dc8d`, `0x3d103b6d`) let any caller control the runtime jump target and the delegatecall implementation. An attacker steers execution into orphan block `0x4a1` and delegatecalls attacker-owned code, executing with the contract's storage and funds — equivalent to full ownership. *Fix:* gate both setters behind access control, and prefer a fixed jump table over storage-derived targets; never delegatecall to an address taken from unauthenticated state.

## Why the combination matters

No single technique gets here. Static analysis flags the opcode but can't tell you it's reachable. A fuzzer without the CFG wastes its budget on the front door. Reachability + computed-jump discovery finds the path; fuzzing + fork replay *proves* it; and Janus — still in development — turns the proof into something a team can act on. That's the BEVM + Janus loop: **find, prove, explain.**

Illustrative example for education. Addresses, blocks, and the ETH figure are synthetic. Only run security testing against contracts you own or are explicitly authorized to test.

[Try it on a contract →](https://app.trilocore.ai/) [Open the workbench](https://app.trilocore.ai/)

[← All research](https://trilocore.com/research/)

---

[Canonical HTML version](https://trilocore.com/posts/orphan-block-delegatecall)
