Safeguard
Product•

IaC Security Checks for Terraform, CloudFormation, Helm and Kubernetes

Check Terraform plans, CloudFormation templates, rendered Helm charts and Kubernetes manifests before deploy, then gate with Block, Warn or Notify.

Safeguard Security Team
36 min read

To catch infrastructure misconfigurations before they reach a cloud account or a cluster, check the files that describe your infrastructure on every pull request: Terraform configuration and, where you can, the Terraform plan; CloudFormation templates; Helm charts after they are rendered with the values you actually deploy; and plain Kubernetes manifests. Then decide which findings stop a merge, which only warn, and which just notify an owner, and run every exception through a written approval with an expiry date. This post walks through that design for a platform team with any toolchain, then shows how Safeguard's IaC checks fit into it.

Key takeaways

  • Infrastructure as code (IaC) is configuration, and every major configuration standard (NIST SP 800-53 CM-2 and CM-6, the NIST SSDF practice PW.9, the Kubernetes Pod Security Standards) expects secure settings to be defined, reviewed and enforced. The pull request is the cheapest place to enforce them.
  • Each format needs a different input. Terraform is best checked as source plus plan JSON. CloudFormation is checked as the template plus parameter files. Helm must be rendered first, because the risky values often live in a values file, not in the chart. Kubernetes manifests are checked as they will be applied.
  • Start new rules on Warn, promote the ones you trust to Block, and keep Notify for owners who need to know but should not hold up a release. Approvals go through exceptions, each with an owner, a reason and an expiry.
  • Safeguard's IaC checks (GA) appear on its Integrations page as Terraform, CloudFormation, Helm and Kubernetes manifest checks. They sit next to source code integrations (GA), CI/CD integration (GA), policies and gates (GA) with Block, Warn and Notify actions and approval through exceptions, and the Safeguard CLI and local runner (GA).
  • Autonomous remediation (GA) ships switched off, with every category set to Manual. Fixes to infrastructure code stay a reviewed pull request.
  • IaC checks see the code, not the live account. Cluster runtime state, cloud drift and in-cluster enforcement are separate jobs that stay with you.

The situation

It is Tuesday afternoon. A developer on the payments team opens a pull request that adds a new S3 bucket for export files, a security group for a reporting service, and a Helm values override that turns on a debug sidecar. The change looks routine. The reviewer is a platform engineer who has seven other pull requests in the queue and an on-call shift starting at six.

What can go wrong in that one pull request is a long list. The bucket might not block public access. The security group might open port 22 to the whole internet because someone copied a rule from a lab environment. The debug sidecar might run as root with a host path mount, because that is how it was easiest to attach a profiler. None of these will fail terraform validate or helm lint. All of them will deploy cleanly. Some of them will show up weeks later in a cloud posture report, a penetration test or, on a bad week, an incident.

The platform engineer wants three things from IaC security:

  1. Fast feedback on the pull request. A comment on the line that matters, while the author still has the change in their head, not a ticket three weeks later.
  2. No surprise blocks. A merge should fail only for rules the team agreed on, and the failure should explain itself. A pipeline that blocks on noise gets bypassed, and a bypassed pipeline is worse than none.
  3. Evidence that holds up. When the auditor or the cloud security team asks "how do you stop public buckets from shipping", the answer should be a rule, a gate and a list of approved exceptions, not a promise.

The rest of this post is built around those three needs.

What the standards ask for

IaC security is not a niche practice invented by tool vendors. It is the configuration management requirements that every major framework already contains, applied to the files that now produce the configuration. Nothing here is legal or audit advice; check the current text of each standard against your own obligations.

NIST SP 800-53 Rev. 5: configuration management controls

The configuration management family in NIST SP 800-53 Rev. 5 is the most direct source. CM-2 asks an organisation to develop, document and maintain a baseline configuration under configuration control. CM-6 asks it to establish and document configuration settings that reflect the most restrictive mode consistent with operational requirements, to implement them, to identify, document and approve any deviations, and to monitor and control changes to those settings. CM-7 asks for least functionality: configure systems to provide only mission essential capabilities and prohibit or restrict the rest. CM-3 covers configuration change control: review proposed changes and approve or disapprove them with explicit consideration for security impact, document the decisions and retain records of the changes.

When the baseline is a Terraform module and the change is a pull request, each of those controls maps onto something concrete. The baseline is the module and its policy rules. The settings are the attributes in the code. Change control is the review and the gate. The approved deviations in CM-6 are your exception list. An IaC check turns the control from a document into a test that runs on every change.

NIST SSDF (SP 800-218): secure settings by default

The Secure Software Development Framework, NIST SP 800-218 version 1.1 (February 2022), includes practice PW.9, "Configure Software to Have Secure Settings by Default." Task PW.9.1 asks producers to define a secure baseline so that default settings are secure and do not weaken the security functions of the platform, network infrastructure or services. Task PW.9.2 asks them to implement and document those defaults. For a platform team, the "software" your users receive is often a module, a chart or a template. If the shared Helm chart ships with privileged: true as a default, every team that installs it inherits that choice.

The SSDF also has practice PO.3, on supporting toolchains. PO.3.1 asks you to specify which tools or tool types each toolchain must include to mitigate identified risks, and PO.3.3 asks you to configure tools to generate artefacts that show your secure development practices are followed. An IaC check in CI that leaves a result per merge does both.

NIST SP 800-204D: security in CI/CD pipelines

NIST SP 800-204D, published in February 2024, covers strategies for integrating software supply chain security into DevSecOps CI/CD pipelines, the flow that takes cloud-native software through build, test, package and deploy. Its keywords include artefact, attestation, provenance and SBOM. Infrastructure definitions that flow through the same pipeline belong in the same discipline: checked as they pass through, with a record of what passed.

Kubernetes Pod Security Standards

The Kubernetes project publishes the Pod Security Standards, three cumulative policy levels: Privileged, Baseline and Restricted. Baseline prevents known privilege escalations, such as host namespaces, privileged containers and host path volumes. Restricted adds current pod hardening practice, such as running as non-root, dropping all capabilities and setting a seccomp profile. These levels are a ready-made rule set for Kubernetes manifests and rendered Helm output (see Baseline vs Restricted). Kubernetes enforces them inside a cluster through its built-in Pod Security Admission controller; checking the same rules in the pull request means the author finds out before the deploy fails.

NSA and CISA Kubernetes Hardening Guidance

NSA and CISA publish a joint Kubernetes Hardening Guide, first released in August 2021 and updated in 2022. CISA describes it as recommended configuration and hardening guidance for setting up and securing a Kubernetes cluster. Much of that guidance concerns how workloads are configured, which means it can be checked in manifests before they are applied rather than discovered in a running cluster.

CIS Benchmarks

The Center for Internet Security publishes consensus configuration benchmarks for cloud platforms and for Kubernetes. Many benchmark recommendations, such as encryption at rest for storage, logging for cloud API activity, and restrictions on administrative ports, correspond to attributes you can check in Terraform or CloudFormation before the resource exists.

OWASP Kubernetes Top Ten

The OWASP Kubernetes Top Ten names common Kubernetes risk categories. Several of them, including K01 Insecure Workload Configurations, K02 Overly Permissive Authorization Configurations and K05 Missing Network Segmentation Controls, usually start life as a line in a YAML file that a reviewer could have read.

What this means for the pull request

Read together, these documents ask for the same loop: write down the secure settings, check every change against them, approve deviations deliberately and keep a record. IaC checks are how you run that loop at the speed of a pull request.

What goes wrong in each format

The four formats in this post look similar (they are all text, mostly YAML or HCL) but they fail in different ways. A rule set that ignores those differences produces both false alarms and blind spots.

Terraform

Terraform describes cloud resources in HashiCorp Configuration Language (HCL). The source code is only part of the story. Variables come from .tfvars files, environment variables and workspace settings. Modules come from registries and Git. Many values are only known after terraform plan resolves them.

Common Terraform misconfigurations that a check should catch:

AreaRisky patternSafer pattern
Object storageBucket without public access blocks, or a policy granting access to everyoneAll public access block settings on, explicit bucket policy
NetworkSecurity group or firewall rule allowing administrative ports from 0.0.0.0/0Source restricted to known ranges or a bastion
IdentityIAM policy with wildcard actions and wildcard resourcesScoped actions on named resources
EncryptionStorage, database or queue without encryption at restEncryption on, with a managed key where required
LoggingCloud audit logging or flow logs disabledLogging on and sent to a protected destination
SecretsPasswords or tokens as plain variable defaultsValues pulled from a secret manager at apply time
ModulesModule source pointing at a Git branch with no pinned refRegistry version or a pinned commit

Two Terraform facts matter for how you scan. First, the Terraform documentation says state and plan files contain detailed information about your infrastructure, including attributes that can hold sensitive values such as initial database passwords or API tokens, so both need the same protection as secrets (more in Terraform saved plan files contain secrets). Second, terraform show -json produces a machine-readable representation of a plan, with resolved values for attributes that were variables in the source. A check against plan JSON sees what will actually be created, which removes a whole class of "it depends on the variable" uncertainty.

CloudFormation

AWS CloudFormation templates are JSON or YAML. Parameters, mappings, conditions and intrinsic functions decide the final resource properties. The same misconfiguration categories apply as for Terraform, with some CloudFormation-specific twists:

  • NoEcho is not a vault. The CloudFormation documentation says NoEcho masks a parameter value in some API and console output, but it does not mask information stored in the Metadata section, Outputs or resource metadata. AWS recommends dynamic references to Secrets Manager or Systems Manager Parameter Store instead of embedding secrets.
  • Stack policies and deletion policies are guardrails, not security controls. They protect resources from accidental update or deletion; they do not restrict who can call CloudFormation.
  • Nested stacks and macros hide content. A check that only reads the top-level template can miss resources defined in nested templates or produced by transforms.

Helm

Helm charts are templates. The chart itself rarely contains the dangerous value. The dangerous value is in values.yaml or, more often, in an environment-specific override file that turns on a feature, raises privileges or mounts a host path. Scanning only the chart directory tells you what the defaults look like, not what you deploy.

The Helm documentation describes helm template, which renders chart templates locally and prints the resulting manifests. That rendered output is the right input for Kubernetes rules. A sensible Helm check therefore runs in two passes: one over the chart with its defaults (to protect everyone who installs it), and one over each rendered combination of chart and values that you actually ship.

Helm also has its own supply chain questions. Charts come from repositories and OCI registries. The Helm documentation describes provenance files and helm verify for checking a chart's integrity against a signing key; that tells you who published the chart, not whether its defaults are safe.

Kubernetes manifests

Plain Kubernetes manifests (Deployments, StatefulSets, DaemonSets, Jobs, Services, Ingresses, Roles and bindings) are the final form for both Helm and many GitOps setups. The Pod Security Standards give you a rule set for workloads. Beyond pods, the usual checks are:

ObjectRisky patternWhy it matters
Pod specprivileged: true, host namespaces, added capabilitiesContainer can reach the node
Pod specNo runAsNonRoot, allowPrivilegeEscalation not set to falseRoot inside the container is closer to root on the node
VolumeshostPath mounts, especially of the container runtime socketDirect path to the node and other workloads
ImagesTag latest or no digestWhat runs can change without a manifest change
ResourcesNo CPU or memory limitsOne workload can starve a node
ServiceType LoadBalancer or NodePort where internal was intendedUnplanned public exposure
RBACWildcard verbs or resources, bindings to cluster-adminOver-broad authority for a service account
Service accountsTokens automounted where the workload never calls the APIToken available to anyone who compromises the pod

Step by step: an IaC check program any platform team can run

These steps work with any toolchain, including scripts you write yourself. They assume your infrastructure code lives in version control and changes through pull requests.

  1. Inventory the IaC you own. List every repository that contains Terraform, CloudFormation, Helm charts, values files or Kubernetes manifests. Include the ones nobody thinks of: the GitOps repository, the platform team's shared modules, the one-off repository a data team uses for a notebook cluster. Note which ones deploy to production.

  2. Decide the input for each format. Use the table in the next section. The short version: Terraform source plus plan JSON where the pipeline can produce a plan; CloudFormation templates plus the parameter files used per environment; Helm rendered per values file; Kubernetes manifests as applied.

  3. Choose a baseline rule set. Start from a published standard rather than from scratch. For Kubernetes workloads, the Pod Security Standards Baseline level is a reasonable floor, with Restricted as the target. For cloud resources, start with the CIS Benchmark for your provider and your own organisation's non-negotiables (no public storage, no administrative ports open to the internet, encryption on).

  4. Map each rule to an action. Every rule gets one of three actions: Block (the merge or deploy stops), Warn (the check reports and the change can proceed), or Notify (an owner is told, nothing is held up). Write the mapping down. New rules start on Warn.

  5. Wire the check into the pull request. Run it on every pull request that touches IaC paths, and post the result where the author is already looking. A comment on the relevant line is better than a link to a dashboard.

  6. Set up the exception path before you turn on Block. An exception needs an owner, a reason, a scope (which resource, which repository), and an expiry date. Without a written path, people find unwritten ones.

  7. Run in Warn for a few weeks and read the results. Look for rules that fire on things nobody will fix (tune or drop them), rules that fire correctly but noisily (consider Notify), and rules that catch real problems (candidates for Block).

  8. Promote trusted rules to Block. Do this one rule at a time, announce it, and keep the exception path visible.

  9. Scan the default branch on a schedule. Pull request checks only see what changes. Rules change, and new rules should be run over existing code. A scheduled scan of the default branch finds the debt.

  10. Keep evidence. Store the rule set, the action mapping, the scan results per merge, and the exception list with approvals. That record is what an auditor or a cloud security team will ask for.

Template: the IaC rule-to-action sheet

Copy this into a shared document and fill it in for your own estate. The rows are illustrative.

RuleFormatSource standardAction todayOwnerReview date
Storage must block public accessTerraform, CloudFormationCIS Benchmark (cloud)BlockPlatformQuarterly
No administrative ports from the internetTerraform, CloudFormationCIS Benchmark (cloud)BlockNetworkQuarterly
IAM policies without wildcard actionsTerraform, CloudFormationNIST SP 800-53 AC-6WarnCloud securityMonthly
Containers run as non-rootHelm (rendered), KubernetesPod Security Standards, RestrictedWarnPlatformMonthly
No privileged containersHelm (rendered), KubernetesPod Security Standards, BaselineBlockPlatformQuarterly
Images pinned by digestHelm (rendered), KubernetesInternal policyNotifyService ownersMonthly
Resource limits setHelm (rendered), KubernetesInternal policyNotifyService ownersQuarterly

Scan the source, the rendered output or the plan?

This is the question platform teams argue about most. Each input sees something different.

InputSeesMissesBest for
Terraform sourceHardcoded values, module sources, resource typesValues from variables, data sources and modules resolved at plan timeFast pull request feedback, module authors
Terraform plan JSONResolved attribute values for what will be created or changedAnything outside this plan; needs cloud credentials to producePre-apply gate in the deploy pipeline
CloudFormation templateResource properties, parameter defaultsValues passed at deploy time, nested stacks not readPull request feedback
CloudFormation template plus parameter filesValues per environmentRuntime changes, transforms not expandedPer-environment gate
Helm chart directoryTemplate defaultsOverrides in values filesChart authors, shared charts
Helm rendered outputWhat will be applied for one values fileOther values combinationsPre-deploy gate per environment
Kubernetes manifestsExactly what will be appliedMutations by admission webhooks in the clusterGitOps repositories

The practical answer is "more than one." Run fast source checks on every pull request for quick feedback, and run the resolved checks (plan JSON, rendered Helm, per-environment parameters) as the gate before deploy. Format-specific walkthroughs: scanning Terraform before apply, scanning a Helm chart for misconfigurations and scanning Kubernetes manifests before deploy.

How to handle exceptions without losing control

Exceptions are not a failure of the program. Some workloads legitimately need privileges: a node monitoring agent may need host namespaces, a storage driver may need host paths. The goal is to make each exception visible and temporary.

A good exception record answers five questions:

  1. Which rule, and which resource or path, does it cover?
  2. Why is it needed, in one or two sentences a reviewer can judge?
  3. Who approved it, and are they someone other than the author?
  4. When does it expire, and who gets reminded?
  5. What compensating control is in place (for example, the workload runs in a dedicated node pool)?

Keep exceptions out of the code where you can. An inline "ignore this rule" comment in a manifest is easy to add and easy to forget. A central exception list with approvals and expiry is harder to abuse. There is a longer treatment in how to handle exceptions to IaC security rules.

What "good" looks like after a quarter

A platform team that has run this for a quarter usually has a short list of Block rules everyone understands, a longer list of Warn rules being tuned, a small, dated exception list, and a scheduled scan that shows the old debt shrinking. The point is not zero findings. The point is that every finding has a known path: fixed, accepted with an expiry, or tuned away for a stated reason.

Where IaC checks sit next to other controls

IaC checks are one layer. It helps to be precise about what each layer sees, so nobody assumes coverage that is not there.

ControlWhen it runsWhat it seesWhat it misses
IaC checks in pull requestsBefore mergeCode and resolved plans or rendered manifestsChanges made outside the code, live state
Pre-apply or pre-deploy gateBefore apply or deployThe exact change about to happenAnything applied by hand
Kubernetes admission in the clusterAt object creationEvery object the API server receivesWhat never reaches the cluster, cloud resources
Cloud posture managementAfter deploy, on a scheduleLive cloud configurationWhy it was configured that way, who changed it in code
Drift detectionAfter deploy, on a scheduleDifferences between code and live stateWhether the code itself was safe

Kubernetes ships Pod Security Admission as a built-in admission controller. Its documentation describes three modes: enforce rejects a violating pod, audit records an annotation in the audit log, and warn shows the user a warning. The layers in this table are compared in more depth in IaC scanning vs CSPM. That cluster-side control is yours to configure. IaC checks in the pull request complement it: the author learns before the deploy, and the cluster still refuses what slips through.

How Safeguard does this

Safeguard lists IaC checks as a security testing integration on its Integrations page, where the card reads "Terraform, CloudFormation, Helm & Kubernetes manifest checks." The steps below follow docs.safeguard.sh as of 25 October 2026 and that card text. The docs do not yet have a dedicated IaC page with screens, rule lists or commands, so where a step depends on IaC detail, this section describes the outcome and what to check in your own workspace instead of inventing a screen. Commands are copied from the docs; we did not run them for this post.

  1. Connect the repositories that hold your infrastructure code (GA). Source code integrations connect GitHub, GitLab, Bitbucket, Azure DevOps, Azure DevOps TFVC, Oracle Cloud DevOps, Subversion, Mercurial, Perforce and any generic Git URL. The docs say integrations are scoped to a team or organisation, with team-level overrides where relevant, so a platform team can connect its shared module and GitOps repositories under its own scope.

  2. Turn on IaC checks (GA). The IaC card on the Integrations page covers Terraform, CloudFormation, Helm and Kubernetes manifests. Before you rely on it, read what it reports for one repository you know well: which files it picked up, whether a Helm finding refers to a chart default or to a values file, and how each finding names the file and resource. That tells you which inputs from the table earlier in this post it covers for your layout, and which you still produce yourself (a plan JSON file, a chart rendered per environment).

  3. Add a scan step to your pipeline with CI/CD integration (GA). The CI/CD docs describe one pipeline step that runs safeguard ci scan, with templates for GitHub Actions, GitLab CI/CD, Bitbucket Pipelines, Jenkins and Azure Pipelines, and a plain shell step for any other CI. There is no plugin, Action or Pipe to install. Setup has three parts: create a secret key under Settings › Developer with the scopes scans:trigger and scans:read, store it in your CI as SAFEGUARD_API_KEY, and add the step. Each push becomes a new version of the Safeguard project, named after the branch and commit. For a CI system without a template, the docs show:

curl -fsSL https://cli.safeguard.sh/install | bash
SAFEGUARD_API_KEY=... safeguard ci scan --wait --fail-on critical \
  --repository-url "$REPO_URL" --branch "$BRANCH" --commit "$COMMIT"

Read the flags carefully. The docs say the default mode scans for SAST, SBOM and dependency vulnerabilities, and --fail-on fails the step on dependency vulnerabilities at or above a severity. They do not say IaC findings are part of --fail-on. To make a pipeline fail on a policy decision, the docs use --wait --fail-on-gate with a gate name, id or all, which fails the job when the gate is not Passed or Warning. Pin the CLI with SAFEGUARD_VERSION on the install line, as the docs suggest, so a release does not change a build under you.

  1. Decide what fails with policies and gates (GA). In the docs, you create a policy under Settings › Policies, define its conditions in the visual builder or YAML, set severity and actions, then save and enable it. Each policy's action decides what a failed policy does to its gate: Block means the gate fails, Warn means the gate passes with a warning naming the policy, and Notify means the gate passes and a notification is sent. That is the same three-way mapping as the rule-to-action sheet above. The policy conditions the docs list are about vulnerabilities, licences, component age and maintenance; IaC rules are not in that table, so check in the policy builder which IaC conditions your workspace offers before you plan your Block list.

  2. Run deviations through exceptions. The documented exception flow is: click Request Exception, select the policy and finding, give a business justification, set an expiration date and submit for approval. Approvers are notified, an approver reviews and decides, and an audit trail is recorded. Compliance reporting covers status by policy, exception history and violation trends. That is close to what NIST SP 800-53 CM-6 asks for when it says to identify, document and approve deviations from established configuration settings.

  3. Check locally with the Safeguard CLI (GA) and local runner (GA). safeguard scan --dir . builds an SBOM for a local directory, matches it against vulnerability data and writes JSON results; it does not fail on findings. Scanning from the interactive terminal with /scan . while signed in sends results to the platform, and the docs say the runner uploads the SBOM and findings, never your source. The CLI docs also describe safeguard detect, which reports misconfigurations in the current directory as a table, JSON or SARIF, with --severity high to show only high and critical. The docs do not say which IaC formats detect reads, so compare its output with the platform's IaC findings before you depend on it.

safeguard detect
safeguard detect --severity high
  1. Send findings where owners work (GA). Ticketing integrations create and sync issues in Jira, Linear, Asana, Notion and Microsoft Project (Planner), and chat integrations send channel notifications to Slack, Discord and Google Chat. Route Notify actions for IaC rules to the owning team's channel, not a central security queue.

  2. Keep fixes as reviewed pull requests. Autonomous remediation (GA) ships switched off, with every category set to Manual. For infrastructure code that is usually the right setting: a change to a security group or a pod security context should be read by a person who knows the service.

  3. Manage Safeguard the way you manage infrastructure. The integrations docs say there is no CLI command for creating integrations yet, and that integrations can be declared through Safeguard's Terraform provider:

resource "safeguard_integration" "github_acme" {
  type  = "github"
  org   = "acme"
  token = var.github_token
}

Keep the token in a secret store and pass it as a variable, as the example does. Remember the Terraform documentation's warning: values passed this way can end up in state and plan files, so the backend that holds this state needs the same protection as the token.

Mapping the program to Safeguard

Step in your programSafeguard pieceLabelWhat you still own
Inventory IaC repositoriesSource code integrationsGADeciding which repositories deploy to production
Check Terraform, CloudFormation, Helm, KubernetesIaC checks on the Integrations pageGAYour baseline rule set, and producing plan JSON or rendered charts where you need them
Check on every pushCI/CD integration (safeguard ci scan)GAPipeline credentials and where the gate sits
Block, Warn, Notify per rulePolicies and gatesGAWhich rules block, and when to promote them
Approved deviationsPolicy exceptions with expiry and audit trailGAWho approves, and the expiry discipline
Local checks before pushingSafeguard CLI, local runnerGADeveloper adoption
Route findings to ownersTicketing and chat integrationsGAOwnership mapping and response times
FixesAutonomous remediation, off by defaultGAReviewing and merging infrastructure changes

What Safeguard does not do

  • It does not see your live cloud account or cluster through IaC checks. IaC checks read code. A setting changed by hand in the console, or an object created with kubectl apply from a laptop, is outside what a code check sees. Use cloud and cluster posture tooling for that, and compare it with the code.
  • It does not enforce inside your cluster. IaC checks run before deploy. In-cluster admission (for example Kubernetes' built-in Pod Security Admission) is configured and owned by you.
  • It does not choose your rules for you. Which rules block, which warn and which only notify is a decision for your platform and security teams. Safeguard enforces the mapping you set.
  • It does not approve exceptions. Exceptions need a human approver who is not the author, a reason and an expiry. Safeguard records and applies them; the judgement is yours.
  • It does not replace review of infrastructure changes. A clean IaC check means no rule fired. It does not mean the architecture is right, the blast radius is acceptable or the change is safe to roll out on a Friday.
  • It does not protect state files. Terraform state and saved plans can contain secrets. Encrypting the backend, restricting access and keeping plan files out of public artefacts remain your job.
  • Its CI severity flag is about dependencies. The CI docs say --fail-on fails a build on dependency vulnerabilities at or above a severity. They do not list IaC findings under that flag, so plan to gate through policies and --fail-on-gate, and confirm in your workspace which IaC rules a gate evaluates.
  • It does not resolve every value that only exists at deploy time. If a value is injected by a deploy tool, a mutating webhook or a transform that never runs in the pipeline, a code check cannot see it. Check the resolved form (plan JSON, rendered manifests) where you can produce it.

Common mistakes

  1. Scanning the Helm chart but not the values you deploy. The chart's defaults may be safe while the production override turns on hostNetwork. Render per values file and check the output.
  2. Turning on Block for every rule on day one. The first week produces a pile of findings in existing code. If all of it blocks, the team learns to bypass the gate. Start on Warn.
  3. Inline ignores with no expiry. A comment that silences a rule forever is an exception nobody approved. Move exceptions to a reviewed list with dates.
  4. Treating terraform validate or helm lint as security checks. Both check syntax and structure. Neither checks whether a bucket is public or a container is privileged.
  5. Checking only the default branch. Release branches and environment branches often carry the overrides that matter.
  6. Forgetting pipeline configuration. The workflow file that runs terraform apply with an administrator role is itself infrastructure. Over-broad pipeline permissions and risky triggers belong in the same review.
  7. Letting state files leak through artefacts. Uploading a plan file as a CI artefact to help debugging can publish secrets to everyone with pipeline read access.
  8. Measuring success by zero findings. A program that reports zero findings is usually one that stopped looking. Measure whether each finding has an owner and a path.

FAQ

What is IaC security scanning?

IaC security scanning checks the files that define infrastructure, such as Terraform, CloudFormation, Helm charts and Kubernetes manifests, for insecure settings before they are applied. Typical findings are public storage, open administrative ports, over-broad permissions, missing encryption and privileged containers.

Should I scan Terraform source or the Terraform plan?

Both, at different points. Source checks are fast and work on every pull request without cloud credentials. Plan JSON checks see resolved values and are the stronger gate before apply. If you can only do one in the pull request, do source; add plan checks in the deploy pipeline.

How do I scan a Helm chart for misconfigurations?

Render it first with the values you deploy (the Helm documentation describes helm template for this), then check the rendered Kubernetes manifests. Also check the chart with its defaults if other teams install it.

Do I still need Pod Security Admission if I check manifests in pull requests?

Yes. Pull request checks catch problems early; in-cluster admission catches anything that reaches the cluster another way. They answer different questions and you want both.

What should block a merge and what should only warn?

Block the small set of rules everyone agrees are never acceptable, such as public storage or privileged containers outside approved namespaces. Warn on rules still being tuned. Notify owners about hygiene items like missing resource limits. Review the mapping regularly.

How do exceptions work in Safeguard?

Safeguard's gate actions are Block, Warn and Notify. When a change needs to proceed despite a Block, the approval runs through an exception: the docs describe selecting the policy and finding, giving a business justification, setting an expiration date and submitting for approval, with approvers notified and an audit trail recorded. Who approves and how long exceptions last is your policy.

Does Safeguard fix IaC misconfigurations automatically?

Autonomous remediation is GA but ships switched off, with every category set to Manual. For infrastructure code, keep fixes as reviewed pull requests.

Can I manage Safeguard integrations with Terraform?

Yes. The Safeguard docs show a safeguard_integration resource in Safeguard's Terraform provider for declaring integrations, since there is no CLI command for creating integrations yet.

Does an IaC check find drift between code and the live account?

No. A code check reads code. Drift is the difference between code and live state, and you need a tool that reads the live account or cluster to see it.

Which standards should my IaC rules map to?

Common anchors are NIST SP 800-53 configuration management controls (CM-2, CM-6, CM-7), NIST SSDF practice PW.9, the Kubernetes Pod Security Standards, the NSA and CISA Kubernetes Hardening Guidance and the CIS Benchmarks for your cloud provider and Kubernetes.

IaC checks catch the configuration you write. The images and packages that configuration deploys carry their own vulnerabilities, and when an upstream fix is slow, the section below describes how Safeguard handles that side of the same release.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.

3. Gold Registry: start from components that are already fixed

Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingSafeguard policies and gates in CI
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo is a real Safeguard CLI session. It installs the CLI, opens the interactive terminal with safeguard, and asks it to fix a lodash CVE in a repository; the CLI reads the finding and advisory, asks before any command that changes something, edits package.json, runs npm install and npm test with approval, prints a summary and pushes nothing, then shows /permissions, /model and /scan .. The demo is about a dependency, but the same approval model is what you want around infrastructure code.

Click through it at your own pace, or open it full screen.

The second demo sets up the local runner on your own machine, approves it with a device code, and then scans from the terminal. Module authors can use the same setup to check a Terraform module or a chart before they open a pull request.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude can use. Platform engineers who review infrastructure changes with an AI assistant can keep that assistant's access to Safeguard scoped the same way.

Click through it at your own pace, or open it full screen.

Quick check

Your Helm chart passes every check, but production pods still run privileged. What is the most likely gap?

The checks ran on the chart with its default values, while the production values file turns on the privileged setting. Render the chart with each values file you deploy and check the rendered manifests.

A team wants to turn on Block for all IaC rules on the first day. What should you suggest instead?

Start new rules on Warn, read a few weeks of results, tune or drop the noisy ones, and promote trusted rules to Block one at a time, with a written exception path in place before the first Block.

Sources

Download Safeguard at safeguard.sh/download and read the product documentation at docs.safeguard.sh/docs.

Last reviewed: 25 October 2026. Product capabilities change; check docs.safeguard.sh for the current state.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.