Mandy Hale

Full stack developer & innovator

All posts

Agentic Coding Essentials Week 3: The security pyramid: prompt, harness, sandbox

tilagentic-codingsecurity
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"dontAsk auto-denies everything (learned this the hard way). default prompts 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 .env and .github writes.

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_KEY

Project-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:

  • cat SSH keys — refused in agent pane
  • Echo out an env variable
  • curl https://example.com — outbound HTTP blocked in agent pane
  • curl -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+C out of the agent pane and restart, you need to run workmux sandbox agent — not just claude. 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.
2026 — Mandy Hale | Full stack web developer and creative problem solver.