Chapter 5 · Part 3

Secrets & sandboxing

Two of the trifecta's three legs are about your data: the private stuff an agent can reach, and the route out. This chapter cuts both — starting with the most valuable target, your credentials.

Keep secrets where the agent can't read them

The injection in chapter 2 worked because a secret was reachable: api-keys.txt sat in a folder the agent could read. The fix is to make sure the agent — and therefore any injection riding inside it — never has the secret in the first place.

The pattern: your tool needs the key, but the agent doesn't. So keep the key in your code and let the tool use it — the agent only names the action, never sees the credential.

the key lives in your code, not the agent's reach
import os

STRIPE_KEY = os.environ["STRIPE_KEY"]     # your process has it; the model never sees it

def refund(order_id: str) -> str:
  """Refund an order. The agent passes an order id — never the key."""
  charge_api.refund(order_id, api_key=STRIPE_KEY)   # your code adds the secret
  return f"Refunded {order_id}."
⚠️Never put a secret in the prompt

Don't paste API keys into the system prompt, a user message, or a file the agent can read to "give it access." Anything in the model's context can be echoed back out by an injection — and it lands in logs and conversation history for good. Secrets stay host-side, added by your tool code at the last moment.

Sandbox anything that runs code or touches the system

If a tool executes code, runs shell commands, or writes files, assume the input is hostile and run it in a box:

💡Sandboxing checklist
  • A restricted account — not your user, definitely not root; only the permissions the tool needs.
  • A container or temp dir — isolate the filesystem so a write can't touch anything important.
  • Timeouts and limits — cap CPU, memory and wall-clock so a runaway tool can't hang or spin.
  • Kill the network — a code-execution tool almost never needs internet; deny it by default.

Close the exit

That last point — deny network by default — is the third leg of the trifecta, and the cheapest to remove. If a tool has no reason to make outbound requests, don't let it. Allow-list the exact hosts a tool genuinely needs and block everything else. Now even a fully hijacked agent that reads your data has nowhere to send it.

Any one leg is enough

You don't have to win every battle. Keep secrets out of reach or gate the dangerous tool or cut the egress — break any single leg and the data-exfiltration attack fails. Defense in depth means doing several, so one lapse isn't fatal.

Your agent is hard to fool into anything useful for an attacker. Last step: prove it, watch it, and ship it.