Giving an AI Coding Agent a Job Without Giving It Your Credentials A developer has published a practical guide to sandboxing AI coding agents inside CI pipelines, providing a repeatable harness with a decision table, a sandbox script using Linux namespaces, and canary tests to verify boundaries hold. The approach treats the agent as an unprivileged remote user, defaulting network and secrets to denied and path-scoping writes. The article was prepared as part of MonkeyCode's product outreach, and the sandboxing is provider-agnostic. There's a conversation happening on DEV right now about what happens when AI agents get more tools and the boundaries around those tools fail. Most of the discussion is philosophical. I want to make it concrete: if you're going to let an AI coding agent run inside your CI pipeline — even on your own infrastructure — what does the actual sandbox look like, and how do you prove it holds? This article walks through a repeatable harness: a decision table for what the agent is allowed to touch, a runnable sandbox script, and a canary test that fails loudly the moment a boundary leaks. Everything here runs on a plain Linux box. An agent that can read your repo and execute shell commands is, from a security standpoint, an unprivileged remote user who happens to be very fast — so treat its environment like you'd treat an untrusted contributor's laptop. Concretely, the three failure modes I care about: Before any code, decide which capabilities the agent actually needs. This is the table I use as a starting point — adjust for your own tasks: | Capability | Code-fix task | Doc-generation task | Dependency-upgrade task | |---|---|---|---| | Read repo files | ✅ | ✅ | ✅ | | Write repo files | ✅ scoped paths | ✅ docs/ only | ✅ lockfiles, manifests | | Execute tests/build | ✅ | ❌ | ✅ | | Network egress | ❌ | ❌ | ✅ package registry only | | Secrets in env | ❌ | ❌ | ❌ use a short-lived token if truly needed | | Git push | ❌ open MR instead | ❌ | ❌ | The pattern: network and secrets default to denied , and writing is always path-scoped. The agent proposes, CI disposes. You need a machine to host the agent loop and a model endpoint. For experimentation, I used MonkeyCode here — it offers free access to coding models and a free server option, which made it cheap to iterate on the harness without burning a budget on my own mistakes. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Check the current product documentation for exactly which models and server limits apply, since availability details change; the sandboxing below is provider-agnostic anyway. The important part isn't where the model lives — it's that the execution environment is locked down regardless. A generous free tier doesn't change the threat model. Below is a minimal, reproducible wrapper using only standard tooling. It runs the agent's working directory read-only-except-scratch, strips the environment, and blocks network with unshare Linux namespaces — no Docker required for the demo, though Docker works too : bash /usr/bin/env bash agent-sandbox.sh — run a command against a repo with minimal privileges. Usage: ./agent-sandbox.sh /path/to/repo "your-agent-command --flag" set -euo pipefail REPO="$ realpath "$1" " CMD="$2" SCRATCH="$ mktemp -d " trap 'rm -rf "$SCRATCH"' EXIT 1. Strip environment: no inherited secrets, no CI tokens. 2. Drop network entirely with a private net namespace. 3. Bind-mount the repo read-only; only $SCRATCH is writable. env -i PATH=/usr/bin:/bin HOME="$SCRATCH" \ unshare --net --mount --map-root-user \ bash -c " mount --bind '$SCRATCH' /tmp 2 /dev/null || true cd '$REPO' $CMD " Notes: env -i is the single highest-value line. Most leaks I've seen discussed are just inherited environment variables. unshare --net removes networking for the whole process tree. If your task legitimately needs a registry the dependency-upgrade row above , replace this with an egress proxy allowlist, not open internet.A sandbox you haven't attacked is a rumor. Plant canaries and assert they never escape: bash /usr/bin/env bash canary-test.sh — boundary checks that must all pass before trusting the harness. set -euo pipefail REPO="$ mktemp -d " echo 'console.log "hello" ' "$REPO/app.js" fail=0 Test 1: a fake secret in the environment must not be readable. export AWS SECRET ACCESS KEY="CANARY-7f3d-not-a-real-key" if ./agent-sandbox.sh "$REPO" 'env' | grep -q "CANARY-7f3d"; then echo "FAIL: secret leaked into sandbox environment"; fail=1 else echo "PASS: environment stripped" fi Test 2: network must be unreachable. if ./agent-sandbox.sh "$REPO" 'curl -sS --max-time 3 https://example.com' 2 /dev/null; then echo "FAIL: network egress succeeded"; fail=1 else echo "PASS: network blocked" fi Test 3: repo must be unchanged after a hostile command. BEFORE=$ sha256sum "$REPO/app.js" | cut -d' ' -f1 ./agent-sandbox.sh "$REPO" 'echo pwned app.js; git init -q . 2 /dev/null || true' || true AFTER=$ sha256sum "$REPO/app.js" | cut -d' ' -f1 if "$BEFORE" = "$AFTER" ; then echo "FAIL: repo was modified"; fail=1 else echo "PASS: repo intact modifications confined to scratch " fi rm -rf "$REPO" exit $fail Run this in CI before any agent job. If any check fails, the agent doesn't run. That ordering matters — most setups test the agent's output but never test the cage. One more canary worth adding once you allow limited egress for package installs: embed a unique fake token in a file the agent reads, then alert if that string ever appears in outbound requests or in the diff the agent produces. Cheap to build, catches both naive leaks and injection-driven ones. The current debate about agent tool boundaries gets a lot more tractable once you write the boundaries down as a table, enforce them with a hundred lines of shell, and attack your own enforcement with canaries before trusting it. The agent platform matters less than the cage. If you want a zero-cost sandbox to try this harness yourself, MonkeyCode's free models and server are one way to get an agent loop running — then point the canary tests at it and see what holds.