Key Takeaway
Pulumi Neo Security shows a safe design for infrastructure agents: the assessment phase is read-only throughout, and remediation writes only a proposed change in a repository. Each proven finding becomes a diff, a preview and a pull request for a human, while deployment stays in the existing reviewed workflow. Copy the separation, not the product.
The sentence that made me stop reading Pulumi's Neo Security announcement was a short one: the assessment phase is read-only throughout. Most agent demos I see start from the opposite end, an agent with a deploy credential that is trusted to be careful. Here the agent that goes looking for exploitable flaws holds no write path at all.
A disclosure first: Neo Security is a research preview for invited customers and I have not run it. This post is a close reading of Pulumi's announcement by Joe Duffy (28 August 2026), the Context API post, and the Neo docs on task modes, pull requests and code reviews, plus GitHub's branch protection docs for the parts you can build yourself. Every claim about Neo is attributed to those pages; the pipeline code is mine and labelled as such.
The pattern: two lanes, and only one of them can write
Neo Security is an agent that looks for exploitable flaws in cloud infrastructure, across providers such as AWS, Azure, Google Cloud and Kubernetes, on infrastructure however it was provisioned. The post splits its work into two lanes. The assessment lane builds a threat model, maps attack vectors and tests them, and the post says that phase is read-only throughout. The remediation lane is the only step that writes, and what it writes is a proposed change in a repository.
The handoff between the lanes is the design. Pulumi writes that a proven finding can become a proposed diff, a preview of changes and a pull request for human review, and that deployment stays in the team's existing reviewed workflow. The agent never crosses from I found it to I applied it. A human and the pipeline you already trust sit in that gap.
What a read-only assessment actually reads
Read-only is not the same as shallow. The announcement lists six planes of evidence Neo synthesises before it keeps a finding, and the table below keeps them in the post's order. The point for design is that every plane is a read: inventory listings, a graph query, source files, logs, policy results and questions put to the cloud provider.
| Plane | What it answers | Caveat stated in the post |
|---|---|---|
| Resource inventory | What exists across accounts, regions and types | Includes resources created outside IaC |
| Reference graph | Which workload carries which identity, which identity reaches which data, which stack manages which resource | Read through the Context API |
| Intent | What the author meant: IaC code, comments, naming, commit and review history | Used when available |
| Runtime state | Logs, metrics, uptime, boot logs and network traffic | Through the tools a platform engineer would use |
| Policy and compliance | Over 150 built-in policies mapped to CIS Controls, NIST SP 800-53, HITRUST CSF and PCI DSS, plus customer policies | Used to look for risk beyond known violations |
| Provider answers | Direct questions to the cloud: Access Analyzer for external reachability, public-access checks, policy simulation | Resolves effective permissions after overlapping rules and SCPs |
The reference graph is the plane you can try today without an invitation, if you have the right plan. Pulumi's Context API is a read-only API that connects Pulumi-managed and discovered resources, stacks and their relationships into a graph. A query is a JSON document with anchor, traverse and return clauses. The example from the Context API post asks which resources are managed through AWS providers older than 7.0.0.
// Context API query, copied from Pulumi's Context API post.
// Read-only: anchor picks the starting nodes, traverse follows edges,
// return chooses what comes back. Nothing here can change a stack.
{
"anchor": {
"nodeType": "resource",
"match": {
"type": "pulumi:providers:aws",
"fields": { "provider_version": { "op": "lt", "value": "7.0.0" } }
}
},
"traverse": [
{
"edgeTypes": ["provided_by"],
"direction": "in", // from the provider back to what it manages
"alias": "managed"
}
],
"return": { "select": ["anchor", "managed"] }
}
// An agent that is not Neo can fetch the query grammar with:
// pulumi api GetGraphQuerySchemaAccess is a precondition, not an afterthought. The post says the API is in public preview for Enterprise and Business Critical organisations, needs Pulumi CLI v3.243.0 or later and a role with the resources:search permission, and limits responses to what the caller can read. Neo runs these queries with the invoking user's permissions, and the vocabulary and limits may change during the preview.
Proven findings, not suspicions
The read-only lane has a quality bar. Neo builds a model, tests each attack vector and keeps what survives, ranked by severity and confidence, and it works to exclude findings that are disproven or that have no consequence. Each kept finding carries its evidence and, where the source is available, a specific code fix. That filter is what makes a pull request per finding bearable instead of a flood.
| Finding (from the anonymised report) | Severity | Confidence |
|---|---|---|
| Deployment federation role grants admin with no subject-claim condition | critical | high |
| Build role trusts source-control OIDC with a wildcard branch claim | high | confirmed |
| Public instance with IMDSv1 and suspected secrets in user data | high | medium |
| Database snapshot shared with an account outside the organisation | medium | confirmed |
| No WAF on internet-facing load balancer or CDN | low | high |
The report in the post lists 14 anonymised findings; the table shows five of them. Notice that confidence is its own column. The suspected-secrets finding is high severity at medium confidence, which tells a reviewer to look before trusting it. Pulumi says it ran Neo on several real production estates and that a single run reconciled thousands of managed resources against discovered inventory. Those are the vendor's own claims, and the post gives no false-positive rate.
Remediation writes one thing: a proposed change
The Neo docs describe what the write lane produces. Neo offers to open a pull request after a preview, and each one includes a title, a description of the problem, a list of modified resources, a summary of the preview output and a link back to the Neo task. It finds the stack's repository through git location tags added to the stack when it is created.
After the pull request opens, nothing about Neo is special. If configured, your existing workflows run on it, including previews, security scans, policy checks and tests; a failing check can be handed back to Neo, which pushes the fix to the same PR; and every change goes through human review before merge. The docs name the benefits as human review, CI/CD validation, collaboration, and an audit trail with rollback.
This is why the pattern generalises beyond Pulumi. The write lane reuses controls you already own: branch protection, required checks, code owners. The agent gets no new privilege to be trusted with, only a new author in a place where authors are already reviewed.
The autonomy dials Neo exposes
Neo Security is the strict end of a wider range. The Neo docs define three task modes, changeable at any point during a task, and a separate Plan Mode that waits for explicit approval before any execution begins. Task modes and Plan Mode are independent, so you can pair Plan Mode with Auto mode to review the approach first and then let Neo run without stopping.
| Action | Review (default) | Balanced | Auto |
|---|---|---|---|
| pulumi preview | Approval required | Not required | Not required |
| pulumi up | Approval required | Approval required | Not required |
| Open a pull request | Approval required | Not required | Not required |
Two other statements in the overview matter more than the table. First, Neo never has more access than you do, only less. Second, a read-only mode removes its ability to change anything at all, and PR-based delivery keeps your branch protection rules and reviewers gating what ships. The assessment lane in Neo Security is that read-only posture applied by design rather than chosen per task.
Read the table as a ladder of trust. Review mode gates three actions, Balanced gates one, Auto gates none. Start every new agent at the top rung and move down only for a class of change you have watched succeed repeatedly.
Building the same split with tools you already have
You do not need Neo to apply the pattern to any agent that touches infrastructure. Everything below is my own sketch, not Pulumi's configuration. The first block is the Context API query copied from the Pulumi post: a read-only question with an anchor, one traversal and a return clause, the shape an assessment agent would run all day.
The second block is the write lane's gate: a workflow that previews every change under infra on a pull request, whoever authored it. It holds no deploy step. The permissions block gives the job read access to contents and write access to pull requests only so it can comment the preview. The inputs are those of the pulumi/actions action, whose latest release when I checked was v7.0.0.
# .github/workflows/iac-preview.yml (my sketch, not Pulumi's config)
# The write lane's gate: every pull request under infra/ gets a preview,
# whoever opened it. There is deliberately no "up" anywhere in this file.
name: iac-preview
on:
pull_request:
paths: ["infra/**"]
permissions:
contents: read # the job only reads the repo...
pull-requests: write # ...and comments the preview on the PR
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: npm ci --prefix infra # install your Pulumi program's deps
- uses: pulumi/actions@v7
with:
command: preview
stack-name: acme/prod
work-dir: infra
comment-on-pr: true
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
# Cloud credentials for a preview should be read-only too.The third block makes review binding. GitHub's docs say branch protection can require a number of approving reviews, require code owner approval for code that has an owner, and require status checks. By default those restrictions do not apply to admins, which is why the sketch sets enforce_admins. The agent's identity should have write access to branches and pull requests, never the right to merge or bypass.
# .github/CODEOWNERS: the people who must approve changes to sensitive paths
/infra/iam/ @acme/security
/infra/network/ @acme/platform
# Branch protection through the REST API. enforce_admins is the line people
# forget: without it the rules do not apply to anyone with admin permission.
gh api -X PUT repos/acme/infra/branches/main/protection --input - <<'EOF'
{
"required_status_checks": { "strict": true, "contexts": ["preview"] },
"enforce_admins": true,
"required_pull_request_reviews": {
"required_approving_review_count": 1,
"require_code_owner_reviews": true,
"dismiss_stale_reviews": true
},
"restrictions": null
}
EOFWhere the pattern breaks
Read-only assessment fails quietly when the agent cannot see the source. Pulumi says intent analysis applies when available and code fixes depend on source being available. The Neo docs add that without a VCS integration Neo cannot see the IaC behind a stack and its proposals are not fully contextualised. Findings about resources created outside IaC have no file to patch, so for those the output is a finding, not a diff.
The second break is the VCS. Neo supports GitHub, Azure DevOps, GitLab and Bitbucket for opening pull requests, but custom VCS integrations let it clone and push, not open pull requests. Neo's code reviews are narrower still: they run on GitHub.com only, and the docs state that Neo does not block the merge. A reviewing agent is advice, so the blocking gate has to be your own required check, as in the sketch above.
Auto mode and admin bypass erase the lane boundary. In Auto mode Neo requests no approvals, including before pulumi up, and by default branch protection does not bind admins. An agent plus an admin token is a deploy credential again. Keep the agent in Review mode and enforce rules for admins.
Finally, the availability limits are real and the evidence is thin. The scan is a research preview open to a small group of invited customers, with the initial scan free during the preview, and Pulumi names multi-cloud, multi-account estates as the best fit. The only results published are the vendor's own, with no independent measurement, so treat the design as proven and the product as unproven.
What to do on Monday
You can adopt the pattern without joining the preview. Work through these in order; each one is small and each one removes a way for an agent to write where it should only read.
- List every agent or bot that holds a credential able to change infrastructure, and note which can run apply or up without a human.
- Give assessment agents a separate read-only identity with no write permission anywhere, and send their findings to a ticket or report.
- Route every proposed fix through a pull request that runs a preview and your policy checks before a human sees it.
- Turn on required reviews, code owners and required checks, and enable the setting that applies them to admins.
- If you use Neo, leave tasks in Review mode, use Plan Mode for multi-stack work, and promote a change class to Balanced only after you have reviewed several of its pull requests.
The rule I carry away: an infrastructure agent may read everything it can prove something from, and may write only a proposal into a place where humans and CI already decide. Neo Security is a vendor's implementation of that rule, in preview and unmeasured by anyone outside Pulumi, but the rule works with any agent and any IaC tool.

