Agentic Coding Essentials Week 3: The security pyramid: prompt, harness, sandbox
Week 3 of the Agentic Coding Essentials course focused on security for agentic workflows.
The three-layer model
Security can be thought of as a pyramid with three layers:
- Prompts (top — weakest): Best practice basics — no secrets in prompts, no sensitive logging. Telling a model to ignore untrusted instructions is not sufficient on its own.
- Harness (middle): Permissions enforced by code (e.g. CLI settings). Limits what an agent can do if an attack succeeds.
- Sandbox (base — strongest): Isolated container environment. Prevents a successful attack from reaching the host system — SSH keys, credentials, etc.
Reflection: Where untrusted input can come from in my projects
- External data sources: web fetches, API responses, database queries
- Downloaded content: cloned repos, packages
- Shell commands executed by the agent
- MCP server responses
- Browser content (web browsing agents)
- Inter-agent communication — shared memory or context written by a compromised agent
My settings.json changes (the harness — middle layer)
Approach: deny everything by default, add permissions back incrementally.
{
"permissions": {
"defaultMode": "default",
"allow": ["Read", "Glob", "Grep"],
"ask": ["Bash", "Write", "Edit"],
"deny": [
"Bash(rm *)",
"Bash(sudo:*)",
"Bash(wget:*)",
"Bash(ssh:*)",
"Read(**/.env)",
"Read(**/*.key)",
"Read(**/*.pem)",
"Read(**/.ssh/**)",
"Write(**/.github/**)",
"Write(**/.env*)",
"WebSearch",
"WebFetch"
],
"disableBypassPermissionsMode": "disable",
"strictKnownMarketplaces": []
}
}Key decisions:
defaultMode: "default"—dontAskauto-denies everything (learned this the hard way).defaultprompts on the permissions I've configured.allow: ["Read", "Glob", "Grep"]— read operations allowed, with explicit denies on sensitive file types (.env,.key,.pem,.sh).ask: ["Bash", "Write", "Edit"]— Bash included even though Claude Code has built-in read-only commands that don't prompt by default. Extra friction, but forces a prompt every time so I can read and approve.deny: ["WebSearch", "WebFetch"]— blocks external web content from being pulled into the project.disableBypassPermissionsMode: "disable"— prevents accidental switch to bypass mode. Works at project or local scope.- Write safeguards: explicit denies on
.envand.githubwrites.
Sandboxing with Workmux (the final layer)
Workmux integrates with tmux and creates sandbox environments for agents. Feels like a whole new system to learn, but the key benefit is isolated environments per agent — reduces risk of getting over-reliant on one provider/config, and reduces risk of a compromised agent reaching the host system.
Config structure
Workmux requires both global and project-level config — the docs outline which settings go where. Important to get right (I spent time stuck here).
Global config:
nerdfont: false
sandbox:
enabled: true
network:
policy: deny
allowed_domains:
- "api.anthropic.com"
- "claude.ai"
- "claude.com"
- "platform.claude.com"
- "api.openai.com"
- "generativelanguage.googleapis.com"
env_passthrough:
- ANTHROPIC_API_KEYProject-level (.workmux.yaml): keeping it light for now — sandbox enabled, target set to the agent pane, and file_symlink for node_modules so each worktree has access to installed npm packages without reinstalling.
How I tested
Cross-tested the same commands inside the agent pane (sandboxed) vs. my terminal pane (not sandboxed). Some examples:
catSSH keys — refused in agent pane- Echo out an env variable
curl https://example.com— outbound HTTP blocked in agent panecurl -s --max-time 5 [https://api.github.com](https://api.github.com/)— outbound network access failed in agent pane
Gotchas
- Make sure Claude is running inside the sandbox. If you
Ctrl+Cout of the agent pane and restart, you need to runworkmux sandbox agent— not justclaude. A few times I accidentally started Claude in the window outside the sandbox. - URL authentication + tmux line breaks. Authenticating via URL is tricky because tmux breaks long URLs across lines. Looking into the URL picker plugin as a fix.
Reflections
- Previously relying only on prompts + default settings — the weakest layer only.
- Security friction felt like a slowdown; now treating it as a necessary baseline.
- Inter-agent communication is an area to understand better before scaling to parallel agents.
- Rules will evolve — loosen or tighten as confidence grows.