TerraformPilot

Infrastructure as Code

Atlantis v0.49.0: Docker Image Changes, 12 Security Fixes, and Breaking Config Rules

Atlantis v0.49.0 drops bundled Terraform/OpenTofu from Docker images and fixes 12 CVEs with breaking behavior. Upgrade checklist and HCL/CLI examples.

LLuca Berton5 min read

Introduction

#

Atlantis v0.49.0 is labeled a breaking release for three reasons: the Docker images no longer ship Terraform or OpenTofu binaries, 12 security advisories are fixed with behavior-changing side effects, and a shell-injection fix that actually shipped in v0.47.1 (#6792) is only now formally documented as breaking. Anyone running a self-hosted Atlantis server for Terraform pull request automation should read this before bumping the version, especially if upgrading from v0.47.0 or earlier.

Full release notes: https://github.com/runatlantis/atlantis/releases/tag/v0.49.0

What Is New

#

Docker images no longer bundle Terraform or OpenTofu

#

The latest, vX.Y.Z, -alpine and -debian tags no longer include a terraform or tofu binary on PATH, and the server sets no default Terraform version anymore. The -alpine-slim and -debian-slim tags introduced in v0.48.0 as a transition step are no longer published; if you pinned one of those, move to the unsuffixed, -alpine or -debian tag. If you build the image yourself, use --target alpine or --target debian (the -slim build targets are gone).

Without a configured version, the server refuses to start:

terraform not found in $PATH. Set --default-tf-version ...

Fix it by telling Atlantis which version to download at startup:

atlantis server \
  --default-tf-version=1.9.5 \
  --default-tf-distribution=opentofu

Or via environment variables / Helm values:

# Helm values.yaml
atlantisUrl: https://atlantis.example.com
defaultTFVersion: "1.9.5"
defaultTFDistribution: opentofu

Repos can still override the server default per-project with terraform_version in atlantis.yaml. If the server cannot reach release hosts (air-gapped environments), mount or COPY a binary into a custom image built FROM ghcr.io/runatlantis/atlantis and set --tf-download=false so Atlantis uses the local binary instead of trying to download one.

Carried-over breaking change from v0.47.1 (#6792): no more shell execution

#

If you are upgrading from v0.47.0 or earlier (not just from v0.48.x), this applies retroactively. Atlantis used to build Terraform/conftest commands as shell strings run via sh -c. As of #6792 (fix for GHSA-rjh2-4xgw-p2hj), commands run as argument vectors:

  • Each extra_args entry is one argument — no shell operators (;, &&, |, redirects), no globbing, no word splitting.
  • $WORKSPACE and $DIR still expand in operator-configured extra_args, but no longer in arguments typed in a PR comment after --.
  • Conftest path and extra_args are still whitespace-split; quote paths containing spaces.

If a workflow relies on shell tricks, split it up or move it into a run step, which still executes with a shell:

# repos.yaml / atlantis.yaml workflow
workflows:
  custom:
    plan:
      steps:
        - run: terraform fmt -check && terraform validate
        - plan:
            extra_args: ["-lock-timeout=60s"]

Server-side repo config: allowed_workflows is now enforced strictly

#

If repos use allow_custom_workflows: true combined with allowed_workflows, Atlantis now checks that every project's workflow key is actually in the allow-list. Configs that previously passed silently can now be rejected:

# server-side repos.yaml
repos:
  - id: github.com/myorg/myrepo
    allow_custom_workflows: true
    allowed_workflows: ["custom", "staging"]

Audit atlantis.yaml in each repo and make sure referenced workflow names match.

GitHub/GHES host validation

#

--gh-hostname must match the host in the repository clone URL. Webhooks whose clone URL points to a different host are now rejected — a common trip-up for GHES deployments behind a different public hostname than the internal one.

Comment arguments locked down

#

-out, -generate-config-out, -state, -state-out and -backup are now always blocked after -- in PR comments, and --blocked-extra-args can no longer be used to unblock them. The -var-file allowlist now applies to apply, import and state rm, not just plan; paths containing .. are refused, and repo symlinks that resolve outside the repository are refused too.

state rm now respects apply/import requirements

#

If state is listed in --allow-commands, state rm must satisfy the project's apply_requirements and import_requirements — it's no longer a free pass.

API changes

#

If --api-secret is set, GET /api/locks now requires the X-Atlantis-Token header. Callers of /api/plan and /api/apply must send clean, repo-relative paths[].directory values — no leading /, no globs.

Approval semantics (GitHub, Gitea)

#

apply_requirements: [approved] now evaluates each reviewer's latest review rather than any historical approval. On Gitea, dismissed and stale approvals no longer count, and any push that changes the diff marks existing approvals stale.

Plans are now hash-bound

#

A plan recorded by v0.49.0 is bound to a hash of its inputs. If the plan file changes between plan and apply, the apply is rejected and the PR must be re-planned — closes a window where a stale plan could be silently applied.

Security

#

12 security advisories are fixed in this release; several change default behavior as described above. There's no single CVE list in the notes beyond GHSA-rjh2-4xgw-p2hj (carried over from v0.47.1) — check the GitHub release page for the full advisory list if you need it for compliance records.

Upgrade Steps

#

Atlantis itself has no Terraform provider version constraint to bump; the "version constraint" here is your deployment manifest (Docker tag or Helm chart version).

# Docker Compose / plain docker run
docker pull ghcr.io/runatlantis/atlantis:v0.49.0
# Helm
# Chart.yaml dependency or values override
image:
  tag: v0.49.0
defaultTFVersion: "1.9.5"
defaultTFDistribution: opentofu

Before rolling out:

  1. Set --default-tf-version (and --default-tf-distribution opentofu if applicable) — do this before switching to the new image tag, or the server won't start.
  2. If upgrading from v0.47.0 or earlier, grep your repos' atlantis.yaml files for extra_args entries that rely on shell operators, globs, or multi-flag strings, and split them into individual entries.
  3. Confirm --gh-hostname matches your GitHub/GHES clone URL host.
  4. Review server-side repos.yaml for allow_custom_workflows + allowed_workflows combinations and verify every project's workflow is listed.
  5. Check project dir values for symlinks pointing outside the repo.
  6. Update internal docs/runbooks: -out, -generate-config-out, -state, -state-out, -backup are blocked in comments; -var-file restrictions now also cover apply, import, state rm.
  7. If calling the HTTP API, update clients to send X-Atlantis-Token (when --api-secret is set) and clean, repo-relative paths[].directory.
terraform init -upgrade

is not applicable to Atlantis itself, but run it inside each repo as usual after confirming the correct Terraform/OpenTofu version is resolved by the server.

Verify

#

After deploying the new image/chart version, confirm the server started cleanly and can resolve a Terraform binary:

kubectl logs deploy/atlantis -n atlantis --tail=50
# or
docker logs atlantis

Look for the absence of the terraform not found in $PATH error, then trigger a real plan from a test PR:

atlantis plan

Confirm the plan comment shows the expected Terraform/OpenTofu version, and that atlantis apply succeeds without a "plan has changed, re-plan required" rejection.

Conclusion

#

v0.49.0 trades convenience for a smaller attack surface: Atlantis no longer owns the Terraform/OpenTofu binary lifecycle, and several long-standing comment-argument and approval behaviors are now enforced strictly rather than loosely. Treat this as a breaking upgrade even if you're coming from v0.48.x — set --default-tf-version first, audit extra_args and repos.yaml allow-lists, and re-run a plan/apply cycle on a test PR before rolling it out broadly.

#Atlantis#Terraform#OpenTofu#Docker#Pull Request Automation#CI/CD

Share this article