Run the Injection Yourself
You don't need to have caught the talk to run this. Everything you need is on this page — nobody needs to be standing next to you for it to make sense. If a seat opens up at a staffed table, grab one; otherwise this gets you through the whole exercise solo.
What you're about to do
There are two tools in this lab. A weather server — low privilege, can't delete anything. And an admin server — high privilege, can delete records, but only after a human approves it.
On paper, a protected record is safe: the weak tool can't reach the delete, and the delete needs a person to say yes.
You're going to destroy a protected record anyway — without touching the admin server's permissions, without bypassing the approval, with the approval genuinely being granted. The weak tool can't pull the trigger. It's going to aim one anyway.
Where are you running this?
Path A — RTV tactic table
4:00–5:00 PT · your own laptop
Grab the bundle yourself and follow “Get armed” below.
git clone https://github.com/redasgard/urd.gitPath B — Ludus-hosted range
walk-up laptops · village-wide
The lab is already deployed. Skip cloning — open a terminal and find it:
find / -maxdepth 4 -iname "lab.sh" 2>/dev/nullEither way, confirm you're armed the same way: ./lab.sh check. One naming trap — it's ./lab.sh, dot-sh. Don't type ./lab alone; in this repo lab is a Python package folder, not a program.
On a Ludus range, if it looks like someone already ran the mission before you — the protected record is already gone — reset it yourself, it's cheap: ./lab.sh clean.
Neither path working, or reading this with no laptop at all? Skip straight to “No laptop? Read the attack instead” further down — you lose nothing.
Land the kill
About ten minutes, five steps.
The control
Prove the tool isn't just allergic to deletes.
./lab.sh baseline
./lab.sh analyze-baselineOpen out/findings/baseline.findings.json — empty findings list. A normal delete, no low-privilege hand on the target, throws no cross-server signal. Keep this in your head as “nothing happened.”
The injection
Watch two lines in the output.
./lab.sh missionThe approval line says origin=not shown — the whole vulnerability in three words. The after-line says present=false — the protected record is gone. On the wire, three sequence numbers carry it: seq 4 names the target, seq 15 deletes it, seq 19 proves it's missing.
The receipt
Pull the finding.
./lab.sh analyzeFind URD-0001. Two fields matter: severity: high, and approval_provenance_status: absent — the approval genuinely had no idea where the target came from.
Prove it's not a trick
Kill the obvious objection yourself: “you planted a marker.”
./lab.sh ablate
./lab.sh analyze-ablatedStill high. evidence_basis drops to plain value_flow — no breadcrumb, and it still fires on the value alone moving from the weak server into the delete.
Meet the one wall that stops this
The re-run puts the shared trace back on the record you started with.
./lab.sh mission
./lab.sh policy-checkfinal_decision=BLOCK. This is provenance-bound approval — the one control that checks who selected the target, not just what it is. Rare. Now you'll recognize it when a target has it.
Your turn — the op
So far you destroyed the target the lab picked. Now pick your own.
Objective: make a different protected record disappear.
⚠️Rules of engagement — what makes this the real technique instead of a cheat: do not edit the admin server, do not edit the host, do not touch the database directly, do not bypass the approval, do not change any tool's permissions. The only thing you may change is what the low-privilege side selects. If you delete something by editing the admin server, you've proven admin can delete — which we knew — and proven nothing about the attack.
Fast way — built-in targets
./lab.sh target-billing
./lab.sh target-customer
./lab.sh target-incidentReal way
Edit the weather server's response text yourself and name a target you choose. Watch it come out the other end inside the privileged delete.
Win condition — all four true
- A different protected record is gone
- Urd reports the finding as HIGH
- approval_provenance_status = absent
- The ablated trace still reports HIGH as value_flow
Bonus, if you land it fast: do it again with no marker from the start, and confirm the ablated trace still holds. That's your first evasion move — exact-value reuse is loud, the real move against a serious detector is transforming the value on the way through instead of passing it verbatim.
No laptop? Read the attack instead
Not a fallback for people who failed — the same exercise, done by reading instead of running. Open these, in order:
examples/traces/compositional.trace.jsonl the wire: seq 4, 15, 19
examples/findings/compositional.findings.json the receipt: URD-0001, HIGH
examples/findings/compositional.ablated.findings.json still HIGH, no marker
examples/findings/compositional.policy.json the one wall: BLOCK
examples/traces/retarget/ four different kills, same method
examples/findings/retarget/Find the same four facts as the win condition above, just read off the files.
Want to go further?
- •
./lab.sh planner-demo— same attack, but a planner decides the target instead of a deterministic host. Closer to how a real agent would run it. - •The external-host adapter (
examples/external-host/) shows how a real captured host trace gets normalized into this format. - •Take the bundle to your next engagement. Urd shows you exactly where a target's agent stack lets a low-trust tool aim a high-trust one — the seam you go in through.
Execution authority and target-selection authority are two different powers, and almost nothing checks the second one.
You just proved it, on a target you picked yourself, without ever touching a permission. Find that seam in your own agent stack.