Terraform External & HTTP Data Source Security Review Prompt
Review Terraform external, http, and local-exec data sources for injection, secret leakage, idempotency, and supply-chain risk.
- Target user
- Platform and security engineers auditing IaC escape hatches
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a senior Terraform engineer and security reviewer who treats every `external`, `http`, and provisioner escape hatch as untrusted until proven safe.
I will provide:
- HCL using `data "external"`, `data "http"`, `local-exec`/`remote-exec` provisioners, or the `template`/`archive` external calls
- Where it runs (local, CI runner, TFC agent) and what identity it runs as
- What the data feeds into (resource args, IAM policy, user_data, etc.)
Your job — review for:
1. **Command / argument injection**:
- `data "external"` programs built from interpolated variables that could inject flags or shell.
- `local-exec` using `command` with unquoted interpolations instead of `environment {}` blocks.
- Any value flowing from a variable/data source into a shell string.
2. **Secret leakage**:
- Secrets passed as CLI args (visible in `ps`, logs, plan output) vs env/stdin.
- `data "external"` results stored in **plaintext in state** — flag any secret returned this way.
- `sensitive = true` missing on outputs that carry the result.
3. **Supply-chain / trust**:
- `data "http"` to a URL without TLS pinning, checksum, or auth — flag as an untrusted fetch that runs every plan.
- External programs pulled from `$PATH` on the runner rather than a pinned, checked-in script.
4. **Idempotency & plan-time side effects**:
- `data "external"` and `data "http"` run during **plan** — flag anything with side effects (writes, mutations, cost).
- Non-deterministic output causing perpetual diffs.
5. **Failure & error handling**:
- External program contract: must emit valid JSON of strings on stdout, exit non-zero with a message on stderr.
- `http` responses not checking `status_code` before use.
6. **The better-native question**:
- Is there a first-class provider/resource that removes the escape hatch entirely? Recommend it.
For each finding give: severity, the exact risky line, an exploit/failure sketch, and a concrete safer rewrite.
Mark DESTRUCTIVE: any interpolation reaching a shell, any secret placed on a command line or returned into state, and any plan-time fetch/exec with side effects.
---
HCL: [PASTE]
Runs as: [identity / runner]
Feeds into: [DESCRIBE]
Run this prompt with AI
Test it, get an AI-improved version, or compare models — live in the Prompt Workspace. No copy-paste.
Why this prompt works
external, http, and local-exec are the escape hatches teams reach for when a provider is missing a feature — and they are where injection, secret leakage, and plan-time side effects hide. This prompt reviews each hatch the way a security engineer would, and pushes back toward native resources.
How to use it
- Find every escape hatch in the module.
- Trace the data flow from variable to shell/URL to state.
- Rewrite to env/stdin, pinned scripts, and checksummed fetches.
- Prefer a native resource wherever one exists.
Useful commands
# Find the escape hatches
grep -rEn 'data "external"|data "http"|local-exec|remote-exec' .
# Confirm whether a returned value landed in state as plaintext
terraform show -json | jq -r '.values.root_module.resources[]
| select(.type == "external") | .values.result'
Injection: command built from interpolation
# RISKY: variable flows into a shell string
resource "null_resource" "bad" {
provisioner "local-exec" {
command = "aws s3 cp s3://bucket/${var.key} ./out" # key can inject flags/shell
}
}
# SAFER: pass values via environment, keep the command static
resource "null_resource" "good" {
provisioner "local-exec" {
command = "./scripts/fetch.sh"
environment = { OBJECT_KEY = var.key } # no interpolation in the command
}
}
Secrets: never on the command line or into state
# RISKY: secret on argv (leaks to ps, logs) and result lands in state
data "external" "token" {
program = ["bash", "-c", "get-token --password ${var.password}"]
}
# SAFER: secret via env/stdin; if you must surface it, mark it sensitive
data "external" "token" {
program = ["${path.module}/scripts/get-token.sh"] # reads secret from env
}
output "token" {
value = data.external.token.result["token"]
sensitive = true
}
HTTP data source: check status and trust
data "http" "allowlist" {
url = "https://config.internal.acme.dev/allowlist.json"
request_headers = { Accept = "application/json" }
}
locals {
# Fail loudly instead of feeding a 500 body into config
allowlist = data.http.allowlist.status_code == 200 ? jsondecode(data.http.allowlist.response_body) : null
}
check "allowlist_reachable" {
assert {
condition = data.http.allowlist.status_code == 200
error_message = "Allowlist endpoint returned ${data.http.allowlist.status_code}."
}
}
Review severity guide
Finding Severity
------------------------------------------------ --------
Secret on argv / returned into state Critical
Variable interpolated into a shell command High
Plan-time http/external with side effects High
http fetch without status/TLS/checksum check Medium
External program from $PATH (not pinned) Medium
Non-idempotent output -> perpetual diff Low/Medium
Common findings this catches
- Secrets in
commandstrings surfacing in CI logs and plan output. data "external"returning credentials stored plaintext in state.data "http"to an unauthenticated URL re-fetched every plan.- Provisioners that could be a native resource (use the provider instead).
- External programs violating the stdin/stdout JSON contract, failing opaquely.
When to escalate
- A secret confirmed written to state → rotate it and scrub state history.
- An escape hatch running as an over-privileged runner identity → tighten IAM.
- A fetch dependency with no integrity control → move it behind a checked-in, pinned artifact.
Related prompts
-
Terraform Provisioners & local-exec Escape Hatch Prompt
Decide when (rarely) to use Terraform provisioners and how to do it safely — local-exec vs remote-exec vs null_resource, idempotency, failure handling, and the native alternatives that almost always beat them.
-
Terraform Secrets & Sensitive Variables Prompt
Manage secrets in Terraform — sensitive flag, ephemeral resources, external secret managers, plan/state masking.
-
Dangerous Terraform Changes Review Prompt
Scan a `terraform plan` output for changes that will silently destroy data, cause outages, or trigger irreversible mutations.
-
Terraform Checkov Custom Policy Authoring Prompt
Write custom Checkov policies for Terraform — Python checks extending BaseResourceCheck and YAML-based policies, a .checkov.yaml config, inline skip suppressions and baselines, then wire soft-fail vs hard-fail gating into CI.
More Terraform prompts & error guides
Browse every Terraform prompt and troubleshooting guide in one place.
Reading prompts? Get all 500 in one free PDF
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.