Skip to content

[REVIEW] iac-security: add Terraform plan/state evidence gates #188

@mlodygbelmondo

Description

@mlodygbelmondo

Skill Being Reviewed

Skill name: iac-security
Skill path: skills/cloud/iac-security/

False Positive Analysis

Benign Terraform configuration that can be over-reported if source files are reviewed without plan/state context:

terraform {
  backend "s3" {
    bucket         = "prod-terraform-state"
    key            = "payments/prod.tfstate"
    region         = "eu-central-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

variable "db_password" {
  type      = string
  sensitive = true
}

resource "aws_db_instance" "payments" {
  identifier = "payments-prod"
  password   = var.db_password
}

Why this is a false positive risk:

The skill correctly warns reviewers not to flag password = var.db_password as a hardcoded secret, and it includes state encryption/locking in the supply-chain summary. But the report template still centers source files and scanner-equivalent rules. A reviewer can over-report a variable reference as a committed secret when the source is clean and the real question is whether sensitive Terraform plan/state artifacts are stored, encrypted, access-controlled, retained, and excluded from pull-request artifacts/logs.

Coverage Gaps

Missed variant 1: sensitive = true hides CLI output but the value still persists in state/plan artifacts

variable "api_token" {
  type      = string
  sensitive = true
}

resource "example_service_token" "deploy" {
  token = var.api_token
}

Why it should be caught:

Terraform's sensitive marking is not a guarantee that secrets are absent from state or saved plan files. The skill mentions state-file secrets as a common pitfall, but it should make plan/state artifact handling first-class evidence: backend type, encryption, locking, access scope, local fallback behavior, artifact retention, CI upload rules, and whether saved tfplan / terraform show -json output is treated as sensitive.

Missed variant 2: Source-only review misses planned destructive or privilege-expanding changes

{
  "resource_changes": [
    {
      "address": "aws_iam_policy.admin",
      "change": {
        "actions": ["update"],
        "before": {"policy": "...limited..."},
        "after": {"policy": "{\"Statement\":[{\"Action\":\"*\",\"Resource\":\"*\"}]}"}
      }
    }
  ]
}

Why it should be caught:

The Terraform JSON plan format exposes resource_changes, actions, before, after, and after_unknown fields that can show effective privilege changes, replacements, public exposure, and unknown-at-apply values. A source-only scan can miss changes introduced through variable files, workspace variables, generated modules, provider defaults, or plan-time data sources. The skill should require reviewers to mark high-impact controls as Not Evaluable from Source Only when no plan/state or equivalent resolved configuration is available.

Missed variant 3: Drift and imported resources are invisible in source review

Source says:
  aws_s3_bucket_public_access_block.block_public_acls = true

Current cloud state:
  bucket policy allows public principal
  resource imported manually after the module was reviewed
  terraform plan shows no change because policy is outside the module path reviewed

Why it should be caught:

IaC source does not always equal deployed state. Manual console changes, imported resources, ignored attributes, external policies, provider defaults, and workspace-specific variables can change the effective security posture. The skill should separate source-code findings from resolved-plan findings and deployed-state/drift findings, with clear evidence confidence for each.

Missed variant 4: IaC scanner suppressions lack owner, expiry, and compensating-control evidence

#checkov:skip=CKV_AWS_20:temporary public access for migration
resource "aws_s3_bucket_acl" "legacy" {
  acl = "public-read"
}

Why it should be caught:

The current prompt-injection notice says suppression comments should be reported rather than honored, which is good. But the output format does not require a suppression register with owner, reason, expiry, ticket/risk acceptance, environment scope, and compensating controls. Without that, a temporary exception can become a permanent blind spot.

Edge Cases

  • Local Terraform state, saved binary plan files, terraform show -json output, CI artifacts, and HCP/Terraform Cloud plan JSON should all be treated as sensitive unless proven otherwise.
  • Some values are legitimately after_unknown until apply; reviewers should not claim a pass when the sensitive or exposure-relevant value is unknown.
  • Remote backends reduce local persistence, but Terraform can still write local state on backend failure or expose plan data through CI artifacts and logs.
  • Provider defaults can make source-only findings wrong in either direction; the review should record whether the finding comes from source, plan, state, or live-cloud evidence.
  • Suppressions may be acceptable for narrow legacy migrations, but only with owner, expiry, scope, and compensating control evidence.

Remediation Quality

  • Fix resolves the vulnerability
  • Fix doesn't introduce new security issues
  • Fix doesn't break functionality
  • Issues found: Add Terraform plan/state evidence handling to the IaC report. Require reviewers to identify sensitive artifacts, backend and locking controls, access/retention scope, plan JSON availability, drift/live-state coverage, and suppression lifecycle evidence. Add Not Evaluable from Source Only outcomes when source files cannot prove effective security state.

Comparison to Other Tools

Tool / Framework Catches this? Notes
Terraform JSON plan output Yes when available Provides resolved resource changes, actions, before/after values, and unknown-at-apply fields.
Checkov / tfsec / KICS source scanning Partial Strong for source anti-patterns, but source scanning alone cannot prove plan/state artifact exposure or live drift.
Terraform remote backend controls Partial Helps protect state, but reviewers still need access, encryption, locking, retention, and local fallback evidence.
Drift detection / cloud posture tools Partial Can catch live misconfiguration, but should be tied back to IaC ownership and ignored/imported resources.

Overall Assessment

Strengths:

  • Broad coverage across Terraform, CloudFormation, Pulumi, and Bicep.
  • Good scanner-equivalent rule framing for Checkov, tfsec, KICS, and cfn-nag.
  • Useful warning that variable references are not the same as hardcoded secrets.
  • Good prompt-injection handling for IaC comments and scanner suppression directives.

Needs improvement:

  • Terraform plan and state artifacts should be treated as sensitive review inputs, not only as a summary row.
  • The output format should separate source, plan, state, and live/drift evidence.
  • The skill should provide Not Evaluable from Source Only outcomes for controls that require resolved variables, provider defaults, workspace settings, or live state.
  • Suppression comments need an exception lifecycle table with owner, expiry, scope, ticket/risk acceptance, and compensating controls.

Priority recommendations:

  1. Add a Plan/State Evidence section with backend, encryption, locking, access scope, CI artifact retention, local fallback, plan JSON source, and redaction status.
  2. Add an evidence-origin field to each finding: Source, Plan, State, Live, or Not Evaluable from Source Only.
  3. Require high-risk Terraform reviews to inspect resource_changes[].change.actions, before, after, and after_unknown from plan JSON when available.
  4. Add a suppression register covering checkov:skip, tfsec:ignore, kics-scan ignore, owner, reason, expiry, environment scope, and compensating controls.

Sources Checked

Bounty Info

  • I have read and agree to the CONTRIBUTING.md bounty terms
  • Preferred payment method: to be provided privately after acceptance

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions