How to stop an AI coding agent from running terraform destroy

An agent that can run terraform apply can run terraform destroy. Here are four layers that each stop it a different way, what each one misses, and the commands we tested.

The short answer

Don’t give the agent credentials that can apply. Let it run terraform plan and hand you the plan; you run the apply. Add prevent_destroy to the resources you can’t lose, put a pre-command hook in the agent that asks before terraform destroy, and attach an explicit deny for delete actions to whatever cloud role the agent does get. Each layer catches something the others miss.

Every MCP tool call goes through your rules first. Here a delete that doesn’t say which rows is stopped before it reaches the database. These are the rules deedglass init starts with; the call is made up.

Why -auto-approve is the risk

terraform destroy deprovisions every object a configuration manages. It is only an alias for terraform apply -destroy, so blocking one spelling and not the other does nothing.1 Normally terraform apply prompts you to approve the plan. With -auto-approve it applies without asking, and HashiCorp’s own page notes that this includes destructive operations such as deleting resources.2

Coding agents don’t sit at an interactive prompt. When an agent hits Terraform’s confirmation, the obvious fix from its point of view is to add -auto-approve and run again. So the prompt that protects a person at a terminal is the first thing an agent learns to skip. The same goes for Pulumi: pulumi destroy --yes approves and performs the destroy after the preview, and --skip-preview drops the preview too.6

Layer 1: let the agent plan, not apply

The cleanest split is by credential. The agent gets credentials that can read state and refresh, and runs:

Code Commands typed in a terminal. The text around it says what happens.

terraform plan -out=tfplan
terraform show -no-color tfplan > plan.txt

You read plan.txt and run terraform apply tfplan yourself, with credentials the agent never sees. If you want to see what a destroy would do, terraform plan -destroy shows the proposed destroy changes without executing them.1

This is the layer that does the most work, because it doesn’t depend on reading the command. An agent with read-only cloud credentials can type terraform destroy -auto-approve and the cloud API refuses each delete.

Layer 2: prevent_destroy and protect

Mark the resources you can’t lose:

Code What the screen or file shows, copied as is.

resource "aws_db_instance" "main" {
  # ...
  lifecycle {
    prevent_destroy = true
  }
}

With this set, Terraform rejects any plan that would destroy the object and returns an error, and terraform destroy stops working for the configuration.3 Pulumi’s equivalent is the protect resource option: a protected resource can’t be deleted directly, and a deployment that tries is an error.5

Know the gaps before you lean on them:

  • Deleting the block defeats it. prevent_destroy does not stop Terraform destroying a resource if you remove its configuration.3 An agent that “cleans up unused resources” by deleting the block, then applies, gets past it.
  • It’s enforced by the tool, not the cloud. Pulumi’s protect never reaches the cloud provider.5 Turn on the provider’s own deletion protection too (RDS, Cloud SQL and others have one).
  • terraform state rm isn’t a destroy. It removes the binding to the real object without destroying it.4 The database keeps running, but Terraform no longer manages it, which is its own kind of mess to clean up.

Layer 3: a pre-command hook

A hook in the agent sees the command before the shell does. We ran Deedglass’s shell guard from 0.13.0 against the Terraform and Pulumi commands an agent is likely to type. “asks” means exit 1 and a decision for you; “nothing” means exit 0 and the agent’s own rules decide.8

Command Answer
terraform destroy asks
terraform apply -destroy -auto-approve asks
terraform destroy -target=aws_instance.web asks
pulumi destroy --yes asks
terraform plan -destroy nothing (it only plans)
terraform state rm aws_db_instance.main nothing

Code What the screen or file shows, copied as is.

$ npx deedglass@0.13.0 guard shell --no-files --command 'terraform apply -destroy -auto-approve'
Deedglass asks first: terraform apply -destroy destroys every resource the configuration manages.
  terraform-destroy  terraform apply -destroy destroys every resource the configuration manages

The Terraform and Pulumi rows are two of the catalog’s 55, each with its source and the date it was checked.8 npx deedglass protect installs the guard in Claude Code, Cursor, Codex CLI, Gemini CLI and Copilot CLI in one step.8 Our walkthrough shows the files it writes.

What a hook can’t see matters just as much. It reads text, so a value known only at run time, such as a Makefile target, a script or an alias, passes untouched.8 make teardown that runs terraform destroy inside it gets no question. And if the hook can’t run, because of a timeout or a missing binary, the command goes ahead unchecked.8 One more limit from the table above: a targeted destroy of one resource gets the same ask as a full one, so the reason the guard gives (“every resource the configuration manages”) overstates a -target run. Read the command, not just the reason.

Layer 4: credentials that can’t delete

If the agent must hold cloud credentials, attach an explicit deny for the delete actions you care about. In AWS, an explicit deny in an identity policy, a permissions boundary or an SCP overrides any allow.7 A sketch for an agent’s role:

Code Data in JSON, the format software uses to pass records and settings.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AgentNeverDeletes",
      "Effect": "Deny",
      "Action": [
        "rds:DeleteDBInstance",
        "rds:DeleteDBCluster",
        "s3:DeleteBucket",
        "ec2:TerminateInstances",
        "dynamodb:DeleteTable"
      ],
      "Resource": "*"
    }
  ]
}

This is the only layer that holds when the command never passes through the agent’s shell tool at all, for example when Terraform runs from a script the agent wrote, or when the agent calls the cloud SDK from Python. Put it in a permissions boundary or SCP, not just the role, if the agent can edit its own IAM policies.

Which layer stops what

Situation Plan-only access prevent_destroy / protect Pre-command hook Explicit deny
terraform destroy -auto-approve typed by the agent stops it stops it asks first stops it
Agent deletes the resource block, then applies stops it misses it misses it (it’s an apply) stops it
make teardown wrapping a destroy stops it stops it misses it stops it
Agent calls the cloud SDK directly stops it if the keys are read-only misses it misses it stops it
terraform state rm allowed misses it misses it not a delete

No single column is all “stops it”. The hook is the cheapest to add and gives the clearest prompt, but the credential layers do the heavy lifting. If you only do one thing today, take apply rights away from the agent. Then add the hook so that the commands it does run get a second look.

Related reading: the same approach for AWS CLI deletes and for kubectl delete, what blast radius means for an agent’s credentials, and the checklist before an agent touches production.

To check a command yourself, run npx deedglass guard shell --no-files --command 'terraform destroy'. It reads the command, never runs it, and needs no account. To grade what an agent can reach on your own machine, run npx deedglass scan (what the grade means). To watch the checks without installing anything, open the playground.

Written with AI assistance and checked against our claims register.

The takeaway

Our hook asked first on terraform destroy, apply -destroy and pulumi destroy, not on state rm; pair it with plan-only credentials and prevent_destroy.

Read nextHow to stop an AI coding agent from running kubectl delete namespace Try it: install in 7 s

Related on this site

More posts

Sources

  1. 1Terraform docs: terraform destroy · developer.hashicorp.com · checked 27 October 2026
  2. 2Terraform docs: terraform apply · developer.hashicorp.com · checked 27 October 2026
  3. 3Terraform docs: the lifecycle meta-argument · developer.hashicorp.com · checked 27 October 2026
  4. 4Terraform docs: terraform state rm · developer.hashicorp.com · checked 27 October 2026
  5. 5Pulumi docs: the protect resource option · pulumi.com · checked 27 October 2026
  6. 6Pulumi docs: pulumi destroy · pulumi.com · checked 27 October 2026
  7. 7AWS IAM: policy evaluation logic · docs.aws.amazon.com · checked 27 October 2026
  8. 8Deedglass docs: The shell guard · docs.deedglass.com · checked 27 October 2026

Published 27 October 2026, sources last checked 27 October 2026. If something here is out of date, write to hello@deedglass.com.

Try it on your own setup

npx deedglass scan

Grades only your own setup. Nothing is uploaded.

Pricing