Est.

Misconfiguration Patterns in Pulumi and CDK Agent Infrastructure

Agent-written infrastructure fails in patterns human review never catches.

· 10 min read
Cover illustration for “Misconfiguration Patterns in Pulumi and CDK Agent Infrastructure”
IaC and Pipeline Security · October 15, 2026 · 10 min read · 2,293 words

The infrastructure that agents write is not a faster version of the infrastructure humans write. It is a different category of object, and it fails in ways that manual review never had to catch. Pulumi's May 2026 release notes put the shift in plain terms: LLMs are now executing more than a fifth of infrastructure deployments, up from virtually zero a year ago, with the expectation that the figure crosses half within the year.

The structural difference rests on three compounding properties. First, agents inherit human-scale access credentials and act on them without pausing for judgment. Second, they operate at volume, generating change at a rate that manual review cannot keep pace with. Third, they follow instruction files and learned patterns, so a single bad default propagates across every project the agent touches rather than staying local to one engineer's decision.

Pulumi and CDK are where this matters most. Both are general-purpose-language IaC frameworks that agents can natively author and operate, which distinguishes them from declarative YAML tools where the execution surface is bounded. A misconfiguration that would appear once in a human workflow appears in every stack an agent creates, at machine speed.

Over-privileged bootstrap and deployment roles in CDK

The CDK bootstrap step creates the over-privilege problem before an agent authors a single application resource. That makes it the earliest and most systemic pattern in the catalog. Running cdk bootstrap provisions a CloudFormationExecutionRole carrying arn:aws:iam::aws:policy/AdministratorAccess, which grants full account access and stands in direct contradiction to least privilege. It also provisions a LookupRole with ReadOnlyAccess, which grants broad read access across the account rather than the narrow set of lookups CDK actually needs. The ReadOnlyAccess policy does carry an explicit deny on kms:Decrypt, but that is a thin consolation when every other read path remains open.

The bootstrap CLI warns about AdministratorAccess. The warning is routinely ignored, which means the permissive default persists into production. Any CI system or agent that can assume the deployment role can then deploy arbitrary CloudFormation stacks with full account permissions. The blast radius is the entire account.

Agents make this worse in a specific way. A human engineer might narrow the bootstrap role once, manually, and then move on. An agent that bootstraps new accounts or regions as part of automated expansion reproduces the over-permissioned defaults at scale, across every new account-region pair it touches. The remediation is established: use a custom bootstrap template that restricts the deployment role to only the services and regions the CDK apps actually use. The default may be defensible for development, but it should never reach production accounts reachable by CI systems or agents.

CDK bootstrap trust-policy context collapse and the SaaS vector

The bootstrap trust-policy collapse is not a single misconfiguration. It is an interaction between two individually valid IAM policies, a classic context collapse that agent-authored multi-tenant SaaS infrastructure is likely to trigger. CDK bootstrap roles follow a predictable naming pattern: cdk-hnb659fds-lookup-role-{account-id}-{region}. The pattern is widely known because CDK use is widespread and the naming is standardized. If you know the account ID and region, you can build the role ARN directly, with no reconnaissance first. Agents and attackers alike get that information for free.

AWS responded with a targeted fix. CDK CLI 2.1026.0 updated the default bootstrap template with a stricter assume-role policy, so calls carrying an ExternalId parameter can no longer assume roles within the same account, and that closes the cross-account trust abuse path. But agents are an amplifying factor here. Agents provisioning multi-tenant or multi-account SaaS infrastructure generate many account-region pairs, each bootstrapped with the same template. If that template predates 2.1026.0, or uses a custom template that does not carry the fix, the entire fleet of bootstrapped accounts is exposed.

One might argue that rotating to a post-2.1026.0 bootstrap template closes this. The answer is that agents operating older stacks will not automatically re-bootstrap. The fix requires an explicit re-bootstrap of every affected account-region pair, and agent-managed estates make that remediation operationally harder to track. The fact that 73% of businesses are now running hybrid cloud infrastructure only widens the surface.

Exposed state backends and stack output leakage in Pulumi and CDK

Both Pulumi and CDK create persistent, queryable stores of infrastructure state, and those stores become de-facto credential stores when access controls are absent or under-scoped. The Pulumi state file contains the full configuration of every managed resource, including properties that hold sensitive values. If the state backend is an S3 bucket with no encryption or fine-grained access controls, anyone with bucket read access can read the state file. A storage misconfiguration becomes credential exposure.

CDK follows a different but parallel mechanism. CDK synthesizes to CloudFormation, and CloudFormation stack outputs are accessible to any IAM principal with cloudformation:DescribeStacks permission across the account. Sensitive values exported as stack outputs, database endpoints, generated credentials, are readable account-wide, not only by the stack's owner.

Agents compound both patterns. An agent that creates stacks programmatically is more likely to export values as stack outputs for downstream consumption by other agents or stacks. The convenience of cross-stack references becomes a systematic leak of sensitive values to anyone with describe permissions. The mitigation is to scope each stack to a short-lived, purpose-built IAM role that can only touch the resources that stack manages, rather than sharing a single long-lived admin credential across stacks and CI jobs. The blast radius of a compromised dependency or leaked token is then bounded by what that token can reach.

Supply-chain execution during deploy: the attack surface general-purpose IaC opens

Because Pulumi and CDK are general-purpose-language frameworks, infrastructure deployment is itself a code execution event. Every imported package runs with cloud account credentials in scope, which turns the dependency graph into an attack surface. The critical structural difference from declarative IaC is the mechanism. In Terraform, provider binaries are pulled from a registry with well-defined interfaces, but a compromised provider binary or the external data source can still run attacker-controlled scripts during terraform plan. But in Pulumi and CDK, the infrastructure program can import arbitrary third-party libraries that execute alongside the framework code at deploy time, with access to whatever credentials the deployment role carries. The target environment for a supply-chain attack is not developer tooling but the cloud provisioning pipeline itself. The Terraform Registry's 7400-plus providers are a wide surface, but they are bounded. The dependency graph of a general-purpose language is not.

Agents amplify this surface. An agent that writes or updates IaC programs will add dependencies so it can do the task. It is unlikely to audit transitive dependency trees before adding a package, and it operates faster than any human reviewer can track. The practical mitigation is to generate a software bill of materials per stack and diff it on every change. That creates an audit trail of exactly which packages had access to which cloud account at which point in time, useful for vulnerability triage and for incident response when a dependency is later flagged. The Hugging Face incident illustrates the pattern in practice: a malicious dataset was among the techniques that carried an agent from initial access to production impact, and while novel vulnerabilities opened the first doors, familiar weaknesses including overbroad roles and reachable credentials determined the blast radius.

Dynamic policy bypass: when policy-as-code runs in the same language as the infrastructure it checks

Policy-as-code in a general-purpose language does not close the misconfiguration surface. It adds a new one, because the policy evaluation runs in the same execution environment as the infrastructure program it is supposed to constrain. Two distinct bypass paths follow. The first is direct: a sufficiently sophisticated attack that compromises the infrastructure program itself, not just a dependency, can manipulate policy evaluation to produce compliant-looking results while deploying non-compliant resources. The second is dynamic: policies that check resource properties can be bypassed through dynamic generation of resource names or configurations that static policy checks do not anticipate. An agent generating resource names programmatically is more likely than a human to produce names that evade pattern-based checks.

This is where the structural advantage of YAML-based IaC tools shows. Their limited expressiveness is also a security property: the policy checks can be more exhaustive because the configuration space is bounded. General-purpose languages make the configuration space open-ended, so the checks can never fully enumerate it. Pulumi CrossGuard does address timing. It runs inside the same engine pass that would create the resource, so a violating resource is never created rather than being flagged after the fact. But that does not resolve the dynamic bypass path if the policy itself can be influenced by the program under evaluation. The strongest objection to the common prescription is that policy-as-code in general-purpose languages is itself a misconfiguration vector. The answer is not to abandon policy-as-code but to run runtime enforcement outside the IaC execution path alongside it, not instead of it.

Agent instruction file drift and the compounding effect of session compaction

Agent instruction files define what commands an agent runs, what it avoids, and how a team builds software. They are themselves a misconfiguration surface, one that drifts silently because it sits outside the review path that already covers pipeline configuration. In a sample of repositories, nearly three quarters of AI configuration files, specifically AGENTS.md files, were changed at most once. Half were never updated at all, and a further 23% were modified only once. The instructions agents follow fall out of sync with the infrastructure and policies they govern as both evolve.

Session compaction compounds the problem. A University of Passau research team found that after a single /compact round, only roughly half of safety instructions survived, even when the prompt explicitly asked to preserve them all. After five rounds, only about one in ten remained. The connection to IaC misconfiguration is direct. An agent whose safety instructions have been compacted away is operating with a degraded constraint set. An agent told at first to use least-privilege roles or avoid exposing state backends may no longer carry those instructions after several compaction cycles. This pattern is structurally different from the others. It does not produce a single misconfigured resource. It progressively weakens the guardrails that would have prevented all the patterns above from being introduced.

Diagram: Safety Instructions Lost to Session Compaction. Visualizes: Visualize how agent safety instructions degrade across compaction cycles.

Why these patterns share a common root: agents inherit human-scale access and act on it without judgment

Every pattern in this catalog is an instance of the same underlying problem. Access models designed for human engineers assume that the credential holder will exercise judgment about what to do with the access. Agents do not exercise that judgment. They act on whatever access they hold, at whatever speed the task requires. The blast-radius consequence is structural: because AI agents can search, summarize, and traverse documents and APIs orders of magnitude faster than humans, any misconfiguration in an agent's permissions creates a blast radius far larger than the same misconfiguration would in a human engineer's hands. Machine credentials in most organizations are rotated infrequently and at lower rates than human credentials, which makes the long-lived credentials that agents typically inherit even more dangerous.

The Hugging Face post-incident response illustrates what remediation looks like at the identity layer. The response blocked pod-level access to the instance metadata service across all workloads, rotated every token and credential, and replaced a single shared connector credential bound to system:masters with per-cluster isolation. Those were structural changes to the access model, not patching of individual misconfigurations. The organizations most exposed are those that have adopted agent-authored IaC at speed without revisiting the access model the agents operate under. The pattern of deployment has changed, but the permissions architecture has not.

What controlling these patterns requires: runtime visibility, scoped credentials, and policy enforcement outside the execution path

The mitigation for each pattern follows directly from its structure, and no single control addresses all of them. Effective defense requires controls at three distinct layers. At the IaC layer, custom CDK bootstrap templates that replace AdministratorAccess with scoped permissions limited to the services and regions the CDK apps actually use. Per-stack, short-lived IAM roles scoped to the resources each stack manages, not shared long-lived admin credentials across stacks and CI jobs. SBOM generation per stack, diffed on every change, to track which packages had access to which account at every point in time. CDK CLI version 2.1026.0 or later in use across all bootstrap operations to carry the stricter assume-role policy. At the pipeline layer, policy enforcement that runs outside the IaC execution path, not only as in-language checks that the infrastructure program can influence, so that bypass through dynamic configuration generation is blocked at a layer the agent cannot reach. Agent instruction files treated as governed pipeline configuration: versioned, reviewed on the same cadence as pipeline config, and tested against the current infrastructure state rather than committed once and left static.

At the runtime layer, real-time visibility into agent behavior across the infrastructure estate, not post-hoc log review, so that anomalous actions such as an agent assuming a role it has never assumed before, or reading state it has no task reason to read, are detectable before they produce impact. Audit logs that attribute actions to specific agent identities within agentic chains, not just to the human principal whose credentials the agent inherited. That closes the accountability gap that anticipatory permissioning makes predictable.

The consensus direction is clear. Automated, pipeline-enforced policy is now the accepted path, not a contested alternative, because manual review cannot scale with agent-driven change velocity. The open question is whether that enforcement runs inside or outside the execution path the agent controls. The patterns are known, the controls exist at each layer, and the gap is organizational will to apply them before agents operate at the scale that makes remediation reactive rather than preventive.

Sources

  1. Building for agentic infrastructure

More in IaC and Pipeline Security