Playbook: Onboarding · Recommended Starting Policies · Threat Model · Tool Policy Examples
Create these under Policies → Tool Policies → Create Policy. Leave User Groups empty to apply org-wide, or scope to a team. The four actions are Audit, Warn, Block, and Require Slack Approval (the last needs the Slack integration). Warn is supported on Claude Code and Copilot only — on other tools, use Audit or Block (Block delivers the same outcome; Warn is just the UX nicety where the agent surfaces an inline confirmation).
This pack covers terminal commands — what your agents run through the shell. For policies on MCP tool calls (GitHub, Slack, Notion, Linear, the filesystem MCP, …), see Tool Policy Examples. For the threat-modelling view of this same pack (the one-pager to share with your security team), see Threat Model. For the reasoning behind each default — why it blocks, warns, or audits — see What each default protects. For platform background, see the Onboarding Playbook.
Live in three steps
Apply the pack
Drop in the whole pack — the high-risk actions enforced, everything else on Audit. The dangerous handful is stopped; routine work is logged, not interrupted.
Watch your agents work
Give it a few days. Every audited action — and every enforced one — lands in Analytics → Tool Use → Terminal Run, attributed to the user and session. Now you can see exactly what your agents do — not guess.
Enforce — stop or confirm
The actions that can cost you a weekend: irreversible operations, production-scoped changes, and hard security boundaries. The agent is stopped — or asked to confirm — before it runs one. The Try it column gives a natural-language prompt you can paste into your AI agent — Claude Code, Cursor, Copilot, etc. — to watch the policy fire end-to-end. The arrow shows the command the agent will issue that Unbound catches.| Policy | Why enforced | Command Family · Match (If) | Try it (prompt → command Unbound catches) |
|---|---|---|---|
| Production cloud destruction | Irreversible teardown of a live environment; no undo | Cloud Destroy · Environment *prod* | “Delete the prod-payments-api CloudFormation stack — we’re done with v1.” → aws cloudformation delete-stack --stack-name prod-payments-api |
| Kubernetes resource deletion | Deletes live cluster resources; trivial to fat-finger | Cloud Destroy · Provider kubectl, Operation delete | “Clean up the test-ns namespace in our cluster.” → kubectl delete namespace test-ns |
| Deployment to production | Ships to prod; one command, real user impact | Cloud Provision · Environment *prod* | “Kick off a CodeDeploy deployment for the webapp application to the prod-app deployment group from s3://releases/webapp/latest.zip.” → aws deploy create-deployment --application-name webapp --deployment-group-name prod-app --s3-location bucket=releases,key=webapp/latest.zip,bundleType=zip |
| kubectl apply to production | Mutates the prod cluster directly, bypassing review | Cloud Provision · Provider kubectl + Environment *prod* | “Apply deployment.yaml against the prod cluster — pass —context prod explicitly.” → kubectl apply -f deployment.yaml --context prod -n prod |
| IAM policy attachment | Grants standing privilege; widens every later blast radius | Cloud IAM · Operation *attach*policy* | “Attach arn:aws:iam::aws:policy/AdministratorAccess to the ci-deploy-role IAM role.” → aws iam attach-role-policy --role-name ci-deploy-role --policy-arn arn:aws:iam::aws:policy/AdministratorAccess |
| Kubernetes RBAC / service-account creation | Rewrites who-can-do-what in the cluster | Cloud IAM · Provider kubectl, Operation create | “Give the build service account cluster-admin so CI can deploy.” → kubectl create clusterrolebinding ci-admin --clusterrole=cluster-admin --serviceaccount=ci:build |
| Secret deletion | A deleted secret can’t be recovered | Cloud Secrets · Operation delete.*|remove.* | “Delete the prod/db/password secret from Secrets Manager.” → aws secretsmanager delete-secret --secret-id prod/db/password |
| kubectl context switch to production | Aims every following command at prod by default | Cloud Config · Provider kubectl, Operation use-context, Environment *prod* | “Switch my kubectl context to the prod cluster.” → kubectl config use-context prod-cluster |
| Cloud project or account switch | Silently redirects later commands to a prod account | Cloud Config · Provider gcloud|aws, Operation set|configure | “Point gcloud at the prod-proj project.” → gcloud config set project prod-proj |
Database DROP | Drops a table irreversibly | Database Admin or Database Write · Operation *DROP* | “Reset the schema for a clean rebuild — run DROP TABLE customers; against local Postgres.” → psql -c "DROP TABLE customers;" |
Database TRUNCATE | Wipes a table’s rows with no undo | Database Admin or Database Write · Operation *TRUNCATE* | “Reset the events table — TRUNCATE TABLE events; so the identity counter resets too.” → psql -c "TRUNCATE TABLE events;" |
| Production database admin | Heavyweight ops on the live database; a bad one is an outage | Database Admin · Environment *prod* | “Reclaim disk on the prod database — run VACUUM FULL.” → psql -h prod-db -U admin -d appdb -c "VACUUM FULL;" |
| Production database writes | Mutates live production data | Database Write · Environment *prod* | “Mark every user in the prod database as inactive.” → psql -h prod-db -U admin -d appdb -c "UPDATE users SET active=false;" |
Database DELETE | An unscoped delete can empty a table | Database Write · Operation *DELETE* | “Delete all rows from the users table.” → psql -c "DELETE FROM users;" |
| Container stop / kill / removal | Tears down a running service | Container Operation · Operation rm|stop|kill | “Force-remove the old auth container.” → docker rm -f auth-api-old |
| Production container operations | Touches a live prod container | Container Operation · Container *prod* | “The prod-api Docker container is hanging — restart it with docker restart prod-api.” → docker restart prod-api |
| SSH to production hosts | Interactive access to a production box | Remote Access · Host *prod*|*production* | “SSH into prod-web-1 and check the nginx logs.” → ssh deploy@prod-web-1 |
| SSH as root | Root shell on a remote host; full control | Remote Access · User root | “SSH into the build server as root to fix the disk.” → ssh root@host |
| Remote script execution on production | Runs arbitrary code on a prod host | Remote Execution · Target Host *prod*|*production* | “Run deploy.sh on prod-host over SSH.” → ssh deploy@prod-host 'bash deploy.sh' |
| Escalate to root | Becomes root; the trust boundary moves and can’t move back | Privilege Escalation · Method sudo|su | “Drop me into an interactive root shell — sudo su -.” → sudo su - |
| Delete files in system paths | Deleting under /etc, /usr, /var, /opt breaks the machine | Delete File · Path /etc/*|/usr/*|/var/*|/opt/* | “Remove the /etc/example config directory.” → rm -rf /etc/example |
Direct push to main/master | Writes to the shared branch without review | Git Action · Operation push + Branch main|master | “Push my fix straight to main.” → git push origin main |
| Modify system files | Edits host config every other process depends on | Update System File · any | “Add a hosts entry pointing api.example.com to 10.0.0.5.” → echo "10.0.0.5 api.example.com" | sudo tee -a /etc/hosts |
Some commands match more than one rule by design — e.g.
kubectl apply --context prod matches both kubectl apply to production and the broader Deployment to production. That’s intentional layered coverage, but it means a single command can be enforced by either. If you’d rather one rule own that path, scope Deployment to production to exclude kubectl (add a provider constraint) once you’ve decided which rule should.Audit — log silently
Routine, but worth a paper trail. These never interrupt anyone — they quietly build the evidence you’ll use to decide what to lock down next. Same demo flow as above — paste the prompt into your agent and watch the matching command land in Analytics → Tool Use → Terminal Run.| Policy | Why audit | Command Family · Match (If) | Try it (prompt → command Unbound logs) |
|---|---|---|---|
| Terraform apply | Provisioning is daily work; log it, don’t wall it | Cloud Provision · Provider terraform, Operation apply | “From infra/terraform/, run terraform apply -auto-approve to roll out the new S3 bucket.” → terraform apply -auto-approve |
| Kubernetes scale | Routine capacity change; worth a record, not a stop | Cloud Provision · Provider kubectl, Operation scale | “Scale the web deployment to 3 replicas.” → kubectl scale deployment web --replicas=3 |
| Helm install / upgrade | Standard deploy step; log to learn the baseline | Cloud Provision · Provider helm, Operation install|upgrade | “Upgrade the payments-api Helm release to the latest chart.” → helm upgrade payments-api ./chart |
| EC2 instance launch | Spinning up infra is normal; track who and what | Cloud Provision · Provider aws, Operation run-instances | “Launch a t3.medium EC2 instance using AMI ami-0abcdef1234567890 for a load test.” → aws ec2 run-instances --image-id ami-0abcdef1234567890 --instance-type t3.medium |
| Secret retrieval | Reading secrets is daily work; log now, tighten later | Cloud Secrets · Operation get-secret-value|read|get-parameter | “Fetch the db-password secret from Secrets Manager.” → aws secretsmanager get-secret-value --secret-id db-password |
| Secret creation or update | Rotation and creation are legitimate; keep a trail | Cloud Secrets · Operation create.*|put.*|update.* | “Create a new Secrets Manager secret called stripe-key.” → aws secretsmanager create-secret --name stripe-key --secret-string "<value>" |
| Vault access | Routine secret reads; visibility before friction | Cloud Secrets · Provider vault | “Read the secret/app/db value from Vault.” → vault kv get secret/app/db |
| Container exec | Devs shell into containers constantly; log, don’t block | Container Operation · Operation exec | “Exec into the running app Docker container with docker exec -it app sh and print env.” → docker exec -it app sh |
| Container image push | Normal publish step; record it | Container Operation · Operation push | “Push the latest image to our registry.” → docker push registry/app:latest |
Database UPDATE | Apps patch rows legitimately; audit, don’t wall | Database Write · Operation *UPDATE* | “Run UPDATE settings SET value = 1000 WHERE key = 'rate_limit'; against Postgres.” → psql -c "UPDATE settings SET value = 1000 WHERE key = 'rate_limit';" |
| IAM access-key creation | Keys rotate during onboarding; track, don’t stop | Cloud IAM · Operation create-access-key|create-login-profile|create-service-specific-credential | “Create a new IAM access key for the ci-user.” → aws iam create-access-key --user-name ci-user |
| Process termination (incl. SIGKILL) | Killing a stuck process is routine; log it | Process Management · any | “Force-kill process 4242 — it’s stuck.” → kill -9 4242 |
| Whole-environment dump | Common debug move, but a real leak risk — keep eyes on it | Environment Exposure · Method env|printenv | “Print my env vars so I can find the SECRET one.” → env | grep SECRET |
| Data upload to external endpoints | Legit uploads and exfiltration look alike; watch the pattern first | Data Transfer · Operation upload|send | “Upload report.csv to https://export.example.com/upload via curl.” → curl -X POST -F "file=@report.csv" https://export.example.com/upload |
| Family-wide Audit rule (Match = any) |
|---|
| Cloud Destroy · Cloud Provision · Cloud IAM |
| Database Admin · Database Write |
| Remote Access · Remote Execution · Privilege Escalation |
| Delete File · Access Password · Environment Exposure · Data Transfer |
These family-wide Audit rules are the biggest driver of analytics volume — they log every classified command in the family. That’s exactly what you want while you’re learning your baseline; once you’ve seen a few days of activity, narrow to the targeted rules above (or add retention/rollup) so the signal stays sharp.
Two layers of coverage
This pack is built in two complementary layers, so a risky operation is caught by one layer or the other:- Precise, production-scoped rules key on the environment Unbound’s classifier reads straight from the command — a host like
prod-db.internal, a container namedprod-api, a namespaceproduction. When a command names its environment, it gets the tighter, production-specific treatment. - Family-wide Audit rules sit underneath every high-risk family (e.g. Audit all cloud resource destruction, Audit all database writes) and log everything that lands in that family, however it’s named.

