Step 1: Stand up DV-ToolAgent and trace one benign ticket
You are the defender on DV-ToolAgent, ACME Cloud's internal operations assistant. It is a real ReAct-style tool-using agent, not a chatbot you talk to directly. A staff member hands it an inbound support ticket and the agent runs a loop:
think the model reads the ticket and the system prompt
call it emits a native tool call (db_query, http_fetch, read_record, memory_*)
dispatch tools.dispatch asks policy.decide(user, tool, args) -> allow / deny / approve
observe the tool result is fed back; the loop repeats until the model answers
Before you defend anything, stand the agent up and trace one benign in-scope ticket so
you know what "normal" looks like. Every later step measures a deviation from this
baseline. Two facts matter here. The agent acts for ticket-bot, the low-privilege
ingest account that processes inbound tickets; it should read account data, not change
it. And there is no secret in the system prompt and no instruction to obey directives
found in a ticket. Every later exploit abuses a tool the agent legitimately exposes,
made the helpful path by congruent ticket wording.
1. Seed the database and memory, then process one benign ticket.
Hit Run, or in the terminal:
python3 dvtoolagent.py --seed
python3 memory_seed.py
python3 dvtoolagent.py "Process inbound ticket: please confirm the billing payee currently on file for the GLOBEX account."
--seed (re)creates /home/labuser/agent.db with the accounts, invoices,
records, and tickets tables. memory_seed.py plants one benign baseline note owned
by finance-clerk. The third call runs the agent once as ticket-bot.
2. Read the TRACE and EFFECTS lines and confirm the action is a read.
A benign confirm-the-payee ticket should drive a single db_query that runs a
SELECT against accounts and returns the GLOBEX row. Nothing should be written. That
confirms in-scope tool use works cleanly before you start attacking it.
3. Read policy.decide, tools.dispatch, and dvtoolagent.run in the source.
tools.dispatch()routes every tool call throughpolicy.decide(user, tool, args)and obeysallow/deny/approve. You will hardenpolicy.py; you do not edit the agent loop, the prompt, ortools.py.policy.decide()is the shipped vulnerable starter: it returnsDecision("allow")for everything. Note that the acting identity istools.CURRENT_USER, set bydvtoolagent.run. You will key the control on it from Step 5 onward.
Pass criteria
The database is seeded (/home/labuser/agent.db exists) and a benign payee-lookup
ticket processed as ticket-bot reads the GLOBEX row without mutating it. That
confirms the agent is live and in-scope tool use is clean.
internal_svc.pylistener.pymemory_seed.pypolicy.pyseed_db.pyticket_ssrf.mdticket_write.mdtools.py