Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/B1.8.mp4Model-authored code runs with the runtime's privileges — reaching the filesystem, the network and any credential in the environment.
Sandboxed execution (B3.2) and egress control (B3.3).
Execute model-authored code and enumerate what the process could touch.
Asking a model to write code is safe. Running the code it wrote is the part that is not, and most agent frameworks ship the second one enabled with the same process privileges as the framework itself.
~/.aws, the HR folder and the roadmap directory, because nothing said otherwise. R6.What it covers. Execute model-authored code and enumerate what the process could touch.
Why a security engineer needs it. Model-authored code runs with the runtime's privileges — reaching the filesystem, the network and any credential in the environment. The control it builds is: sandboxed execution (B3.2) and egress control (B3.3).
This is a risk lesson: it shows the failure happening before anything tries to stop it, so the control that follows is answering something you have already watched go wrong.
Model-authored code runs with the runtime's privileges, reaching the filesystem, the network and every credential mounted there.
Execute in an isolate with no ambient credentials and no default network, and control egress underneath it.
Share of code-executing runs inside an isolate, and the number of credentials visible from within one — target zero.
Measure this
| what to measure | denominator or target |
|---|---|
| code-executing runs inside an isolate | share of such runs |
| credentials visible from inside an isolate | count; target zero |
model ---> "here is a script that does it" ---> agent runtime
|
exec() on the host
v
whatever the PROCESS can reach:
files . network . credentials . socket
writing the code is safe. running it is the part that is not.OWASP T11 — Unexpected RCE and Code Attacks. LLM05 — Improper Output Handling.
Many useful agents write code and run it — that is what makes a data-analysis agent or a coding agent worth having. The agent_runtime component executes text the model produced, on a host, in a process.
The risk is not exotic. Model-authored code is just code, and it runs with whatever the process has: the filesystem it can see, the network it can reach, and every credential in its environment. There is no privilege boundary between "the code the agent wrote to reformat a CSV" and "the code that reads ~/.aws/credentials", because both are strings passed to the same interpreter.
Two paths lead here, and only one involves an attacker:
Steered. An injection from B1.3 tells the agent to write particular code. The runtime executes it because executing code is its job.
Unsteered. Nobody attacked anything. The agent wrote something plausible and wrong — a cleanup routine with a path variable that resolves higher than intended — and the blast radius was decided by the environment, not by intent.
That second path is worth sitting with. Most teams model this as an attack. In practice the first incident is usually an ordinary bug with production credentials in scope, which is why the control in B3.2 is about what the process can reach, not about what the model can be persuaded to write.
Where this lands on the reference architecture. `` ingress -> orchestrator -> agent_runtime -> model | | messaging tools / mcp | | knowledge / memory egress identity + policy wrap every call · observability records it ``
What the executing process can reach, enumerated rather than assumed. Nothing below actually touches your machine — the environment is a fixture, so the lesson runs anywhere.
CyberTravels' Coding Agent runs code it wrote. The skill enumerates what that process reaches — environment, filesystem, network — on an ordinary task first, because the ordinary task is the more persuasive half of the finding.
The skill — skills/threats/generated-code-reach-enumerator/SKILL.md
name: generated-code-reach-enumerator
description: >-
Enumerate what model-authored code can read, write and connect to when it
executes — on an ordinary task and on a steered one — including process
environment, filesystem and cloud metadata. Use when an agent runs code it
wrote, or when sizing the runtime that code should execute in.
allowed-tools: Read, Grep, Glob, BashAn agent that executes its own code has the process's reach, not the task's. The interesting measurement is that an ordinary, unattacked task already touches everything the process can see; steering only changes what it does with that reach, not how much of it there is.
Any agent with a code-execution tool, a notebook runner, a build step it authors, or a shell. Run it before choosing a sandbox, because the output is the requirement list for one.
1 — Inventory the process environment. Every variable visible to the executing process. Credentials in the environment are reachable by any line of code, and the agent did not have to look for them.
2 — Inventory filesystem reach. What the process can open, not what the task needs. Include the agent's own configuration, adjacent workspaces, and any key material mounted for another purpose.
3 — Inventory network reach. Resolve and attempt each destination the process can open. The cloud metadata address is the one that turns a code execution into a credential theft; test it explicitly.
4 — Run the benign task and record what it touched. This is the number that changes the conversation: an ordinary task with no adversary reaching a private key is a design fact, not an incident.
5 — Run the steered task and diff. The difference between the two is what an attacker gains. It is usually smaller than people expect, because the ordinary run already had everything.
Input — the fixture committed at the top of scripts/generated_code_reach_enumerator.py. Edit it and re-run: the buckets, counts and verdicts below are derived from it, not hard-coded.
Output — the opening lines of a real run:
ordinary bug / benign task:
code : rows = open('/home/agent/work/data.csv').read()
reached: 3 things
file:/etc/passwd
file:/home/agent/.ssh/id_ed25519
file:/home/agent/work/data.csv
steered by an injection:
The run continues past this. test_skills.py executes the script on every build, with no model configured — so what CI proves is that it runs and refuses legibly, not that it prints these lines. The output above is a recorded run against a real model, and nothing re-diffs it: a model's answer is not reproducible, and this repository does not claim otherwise anywhere it can be checked.
{
"environment": {"variables": ["str"], "credential_shaped": ["str"]},
"filesystem": {"readable": ["str"], "sensitive": ["str"]},
"network": {"reachable": ["str"], "metadata_endpoint": true},
"benign_run": {"touched": ["str"]},
"steered_run": {"touched": ["str"], "gain_over_benign": ["str"]},
"sandbox_requirements": ["str"]
}
Three ways to do this lesson. Pick one. They run the same procedure against the same code — what changes is who drives it, and how much you see.
The agent reads the lesson, explains the idea, fetches the code, runs the check and answers your questions as you go. This is the one to take if you are here to learn.
Install it, once. From the folder you cloned. --all does every agent it finds on your machine:
python3 scripts/install_skills.py --all --lessons B1.8Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick b1-8-malicious-code-execution:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons B1.8 | type /b1-8-malicious-code-execution |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons B1.8 | type /b1-8-malicious-code-execution in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons B1.8 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons B1.8 | type $b1-8-malicious-code-execution, or run /skills |
No agent, no conversation. The same lesson executes and prints the same readback. Take this one if you have no assistant, if you are reviewing rather than learning, or if you want the result without the teaching around it.
python3 scripts/lesson.py B1.8Neither of the above, and no model needed. The first command writes CyberTravels exactly as it stood at the end of this lesson; the second prints the diff — the lines this lesson added or changed, and nothing from any later one.
python3 scripts/checkpoint.py --at B1.8 --out work/cybertravels
python3 scripts/checkpoint.py --at B1.8 --diffOn Windows, type python wherever these say python3 — and use \ instead of / in the paths. Everything else is identical. A0.0 step 2 explains why.
Ways 1 and 2 need a model; way 3 does not. A signed-in Claude Code CLI needs no API key, and any OpenAI-compatible endpoint works too. With neither, the audit exits 2 and says so rather than inventing an answer. A0.0 sets this up.
Ways 1 and 2 both end with the same readback: What I did, What changed, The number and Read this next. A step that was skipped or refused is reported as exactly that, never as a pass.
If you did the last lesson’s challenge, expect this to stop. Most challenges ask you to edit the code, and ways 1 and 2 will not overwrite your edits: you get stopped, not a failure, with two options — --out for a fresh folder that keeps your work, or --force to discard it and start this lesson clean.
Model-authored code is executed against a fixture environment and the reach is enumerated: an ordinary, unattacked task touches every file the process can see including a private key, and steered code reaches the environment credentials and the cloud metadata address.
For one agent that executes code, list what is in its process environment right now. The credentials in that list are the blast radius of the next ordinary bug, not of the next attack.
Tools used
Skill source: skills/threats/generated-code-reach-enumerator