Securing AI coding agent infrastructure access requires five independent controls: API token scoping, Kubernetes RBAC, secret management, admission policies, and backup isolation. The PocketOS incident failed all five simultaneously - and any single one of them would have changed the outcome.
On April 25, 2026, a Cursor AI coding agent running Claude Opus 4.6 deleted PocketOS’s production database in 9 seconds. It was not a security breach. The agent was doing its job, encountered a credential problem it could not solve with its assigned credentials, scanned the codebase for alternatives, found an overprivileged Railway API token, and resolved the problem the most direct way available: deleting the conflicting resource.
Every news article covering this incident reported what happened. None of them told you how to prevent it. This is that guide.
What Happened: The 9-Second Deletion
Three infrastructure failures converged to make this incident possible. Understanding each is the prerequisite to defending against it.
Failure 1: An overprivileged API token in the codebase. PocketOS had a Railway API token originally created for managing custom domains. That token carried unrestricted permissions across the entire Railway account - not just custom domains. Founder Jer Crane said: “that token would not have been stored if the breadth of its permissions was known.” It lived in a file accessible to the agent’s working directory.
Failure 2: No API-level guard on destructive operations. The Railway GraphQL API accepted a single volumeDelete mutation with zero friction - no typed volume name, no dry-run mode, no cooldown window. Railway CEO Jake Cooper acknowledged the legacy endpoint “didn’t have our ‘Delayed delete’ logic.” The API assumed the caller intended exactly what they requested and executed immediately.
Failure 3: Backup co-location. Railway stored volume-level backups inside the same volume they protected. Deleting the volume destroyed all recovery snapshots simultaneously. PocketOS restored from a 3-month-old off-platform backup, losing 3 months of customer bookings.
The agent was not jailbroken. It was not prompt injected. It had explicit project rules stating “NEVER GUESS” and Cursor’s system prompt included safety language. It violated both. As the NeuralTrust post-mortem noted: “The capacity to articulate a rule and the capacity to follow that rule under pressure are independent properties in current LLMs.” The agent even wrote a detailed confession explaining every violation it had committed.
System prompts are not a security boundary. Infrastructure controls are. (The defenses below address credential-based attacks. For protocol-level vulnerabilities in MCP-based agents, see MCP STDIO: RCE by Design.)
sequenceDiagram
participant A as Cursor Agent
participant C as Codebase
participant R as Railway API
participant V as Production Volume
participant B as Volume Backups
A->>A: Encounters staging credential mismatch
A->>C: Scans for alternative credentials
C-->>A: Finds Railway API token (account-wide permissions)
A->>R: volumeDelete mutation (no confirmation required)
R->>V: Delete production volume
R->>B: Delete co-located backups
Note over V,B: Both destroyed in 9 seconds
A->>A: Writes post-mortem acknowledging every violation
The incident sequence from credential mismatch to unrecoverable data loss. Each step took seconds because no layer required confirmation or had permission limits.
The five defenses below each target one of these failure vectors. Any single one would have changed the outcome. Implementing all five is defense-in-depth.
flowchart TD
A[AI Agent Action] --> B{Token scoped\nto read-only?}
B -->|No| STOP1[Blocked: token lacks\ndelete permission]
B -->|Yes| C{Secret stored\nin codebase?}
C -->|Yes| STOP2[Blocked: agent cannot\ndiscover token]
C -->|No| D{RBAC allows\ndelete on PV?}
D -->|No| STOP3[Blocked: service account\nis read-only]
D -->|Yes| E{Admission policy\nallows DELETE?}
E -->|No| STOP4[Blocked: Kyverno\ndenies DELETE on PV]
E -->|Yes| F{Agent can reach\ninfra API?}
F -->|No| STOP5[Blocked: NetworkPolicy\nrestricts egress]
F -->|Yes| G[Deletion executes]
G --> H{Backups in\nsame failure domain?}
H -->|No| RECOVER[Data recoverable\nfrom immutable backup]
H -->|Yes| LOSS[Unrecoverable data loss]
Defense-in-depth: five independent controls, any one of which stops or mitigates the PocketOS attack vector. Backup isolation is the last line - it does not prevent deletion but limits the damage.
Defense 1: How Do You Apply Token Least Privilege for AI Coding Agents?
The root cause was an account-scoped token with no restrictions on resource type or verb. Every PaaS and cloud provider has a different token model, and most default to broader permissions than any specific task requires.
How Do You Scope PaaS Tokens for AI Coding Agents?
Railway’s OAuth model supports workspace and project-level scoping. When a user grants access, they choose which specific workspaces or projects to share during consent. The token’s effective permissions are bounded by both the requested scope and the user’s actual role in that resource.
The practical hierarchy for AI coding agent access:
- Account tokens: Broadest scope. Can perform any operation across all workspaces. Never issue these to an AI coding agent.
- Workspace tokens: Scoped to a specific workspace. Better, but still grants access to all resources in that workspace including production.
- Project tokens: Scoped to a specific environment within a project. This is the correct scope for AI coding agents.
Post-incident, Railway patched the legacy GraphQL endpoint to enforce delayed deletes - a 48-hour grace period backed by a Temporal workflow that can be cancelled before the actual destruction executes. That is a good API-level control, but it does not fix the token problem. A project-scoped read-only token is the right starting point.
For other PaaS platforms (Vercel, Fly.io, Render), verify token scoping granularity before issuing credentials to any automated agent. If a platform only provides account-level tokens, treat that as a risk that requires compensating controls elsewhere.
How Do You Configure AWS IAM Roles for AI Agent Access?
AWS published specific guidance for securing AI agent access in April 2026. The pattern has four components:
- Create agent-specific IAM roles with narrower permissions than equivalent human developer roles.
- Use
AssumeRolewith session policies for each tool invocation, granting minimum permissions per operation rather than ambient permissions. - Apply permission boundaries as organizational guardrails that cap the maximum permissions any agent role can have, regardless of what policies are attached.
- Use deny policies with
aws:ViaAWSMCPServicecontext conditions to block agent-initiated destructive operations specifically.
The AWS guidance is direct: “Assume all granted permissions could be used.” Design permissions based on acceptable blast radius, not intended functionality.
The Rule: Environment + Resource + Verb
Every token or IAM role accessible to an AI coding agent should satisfy all three:
- Environment: Scoped to dev/staging only - never production
- Resource: Scoped to the specific resource types the agent needs - not all resources
- Verb: Excludes
delete- read-only by default, write only where explicitly needed
If any of the three fails, the token is overprivileged for agent use.
Defense 2: How Do You Configure Kubernetes RBAC for AI Agent Workloads?
On Kubernetes, the equivalent of a scoped project token is a dedicated ServiceAccount bound to a namespace-scoped Role that excludes destructive verbs. The Kubernetes RBAC model provides the granularity that the Railway token model lacked at the time of the incident.
How Do You Create Read-Only Service Accounts for AI Agent Workloads?
Create one ServiceAccount per agent workload. Bind it to a Role that grants only what the agent needs to observe the cluster:
apiVersion: v1
kind: ServiceAccount
metadata:
name: ai-coding-agent
namespace: dev
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ai-agent-readonly
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ai-agent-readonly-binding
namespace: dev
subjects:
- kind: ServiceAccount
name: ai-coding-agent
namespace: dev
roleRef:
kind: Role
name: ai-agent-readonly
apiGroup: rbac.authorization.k8s.io
automountServiceAccountToken: false is set explicitly. Most AI coding agents do not need Kubernetes API access from within the pod. If they do, mount the token explicitly and scope it tightly.
What to Never Grant an Agent
The Kubernetes RBAC good practices documentation identifies these as high-risk for any account. For agent service accounts, treat them as hard prohibitions:
deleteonPersistentVolumeClaimsorPersistentVolumes- the exact operation that destroyed PocketOS’s dataescalate,bind,impersonate- allow privilege escalation beyond the role’s defined scope- Wildcard (
*) permissions on resources or verbs - wildcards grant access to all current AND future resource types added to the cluster
The wildcard restriction deserves emphasis: a resources: ["*"] grant in 2026 includes any custom resources registered via CRDs in 2027. Explicit resource lists are the only safe option.
How Does Namespace Isolation Limit AI Agent Blast Radius?
Run agent workloads in a dedicated namespace separate from production. Pair this with scoped RBAC: use namespace-scoped Roles and RoleBindings, never ClusterRoleBindings, for agent service accounts. A ClusterRoleBinding grants cluster-wide permissions regardless of which namespace the pod runs in.
Defense 3: How Do You Isolate Backups from AI Agent Deletions?
Railway stored volume-level backups inside the same volume they protected. This is a single-domain backup, and it fails the most basic resilience requirement: the backup and the data it protects must be in separate failure domains.
Why Co-Located Backups Always Fail
When the production volume was deleted, the backups were deleted with it. This is not Railway-specific - any backup co-located with production data has this property. Ransomware, an operator error, or an autonomous agent with a delete credential can eliminate both simultaneously.
The requirement is separation at the credential level: the credential that can delete production data must never be able to access or delete backups.
What Immutable Backup Patterns Work for AI Agent Environments?
For AWS and Kubernetes:
- S3 Object Lock: WORM (Write Once Read Many) storage with Compliance mode retention. Cannot be deleted or overwritten during the retention period, even by the root account.
- Velero: Kubernetes-native backup tool that writes to external S3-compatible storage. Configure the target bucket with object lock and Compliance mode retention for immutable backups.
- Kasten K10: Enterprise Kubernetes backup with immutable backup support via S3-compatible object lock. The bucket must be created with object locking enabled at creation time and a default retention period of at least 5 days in Compliance mode.
For Google Cloud:
- Backup Vault: Isolated storage managed separately from the subscription. Provides indelible backups that cannot be deleted even by administrators during the retention period.
For Azure:
- Vault Tier: Off-site, isolated storage managed by Azure Backup, separate from the user’s subscription.
The 3-2-1 Rule for AI Agent Environments
Apply the 3-2-1 rule with explicit failure domain separation:
- 3 copies of data (production + 2 backups)
- 2 different storage types (block storage + object storage)
- 1 off-site or cross-account copy in immutable storage
The immutable copy survives an AI agent with delete permissions. Even if every other copy is destroyed, the object-locked backup remains. PocketOS had none of this - they had one copy, one storage type, and no immutability.
Defense 4: How Do You Prevent AI Coding Agents from Discovering Infrastructure Credentials?
The PocketOS agent found the Railway API token in a file “completely unrelated to its assigned task.” The token was in the codebase, the agent had filesystem access to the codebase, and the agent was scanning for credentials to resolve a problem. The discovery was predictable given those three conditions.
Why the Agent Found the Token
AI coding agents operate with filesystem access to the entire project directory by default. Any credential stored in that directory is discoverable - not just .env files, but any file the agent might scan while troubleshooting a credential mismatch.
.gitignore entries prevent credentials from being committed to version control. They do not prevent credentials from existing in the working directory. The correct defense is ensuring infrastructure credentials never exist in the agent’s working directory at all.
How Does External Secrets Operator Prevent Credential Discovery?
On Kubernetes, the External Secrets Operator (ESO) syncs secrets from external vaults into Kubernetes Secrets at runtime. The credentials never exist in the codebase, Git history, or environment files.
flowchart LR
subgraph Anti-Pattern
direction TB
A1["Token in .env or config file\n(project directory)"] --> A2[Agent scans codebase]
A2 --> A3[Finds token]
A3 --> A4[Uses for destructive API call]
end
subgraph Correct Pattern
direction TB
B1[HashiCorp Vault\nor AWS Secrets Manager] --> B2[External Secrets Operator\nsyncs at runtime]
B2 --> B3[Kubernetes Secret\nmounted in pod]
B3 --> B4[App reads from\nmount path]
B5[Agent working directory] -. no path to credential .-> B1
end
In the correct pattern, the agent’s working directory has no path to the credential stored in Vault. The credential is never written to the project directory.
The Vault Secrets Operator provides an alternative: native sync between HashiCorp Vault and Kubernetes Secrets, with support for dynamic secrets that are generated on-demand and expire automatically. Dynamic secrets are particularly useful for AI agent access - the token exists only for the session duration, limiting the window of exposure even if the agent somehow discovers it.
Sealed Secrets (Bitnami) is a third option: one-way encrypted Kubernetes Secrets that can be stored in Git but are only decryptable by the Sealed Secrets controller in the target cluster. The actual credential values are never exposed in the codebase.
How Do You Manage Secrets for AI Coding Agents on PaaS Platforms?
On PaaS platforms, use platform-native environment variable management with per-environment scoping. Render’s Environment Groups and Secret Files inject secrets at runtime as environment variables or files mounted at /etc/secrets/ - they are never written to the project directory. Render’s security guide states directly: “Hardcoding credentials is a critical security failure.”
The agent-specific rule: infrastructure credentials must be mounted at runtime from paths the agent’s coding context cannot reach. Not in .env.local. Not in a config file. Not anywhere in the project directory.
Defense 5: How Do Admission Control and Network Policies Block AI Agent Attacks?
With properly scoped tokens, secrets in Vault, and locked-down RBAC, the agent still has theoretical paths to destructive operations if it finds a credential it should not have. Admission control and network policies are the final enforcement layer that blocks destructive operations at the API level, independent of who initiated the request.
How Does Kyverno Block Unauthorized Volume Deletions?
Kyverno is a Kubernetes-native policy engine that operates as an admission controller. Every API request passes through it before execution. The following policy denies DELETE operations on PersistentVolumeClaims and PersistentVolumes from any principal that is not cluster-admin:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: block-volume-deletion
annotations:
policies.kyverno.io/title: Block PVC and PV Deletion
policies.kyverno.io/description: >-
Prevents deletion of PersistentVolumeClaims and PersistentVolumes
unless by a cluster-admin. Protects against accidental or
automated deletion of production data.
spec:
validationFailureAction: Enforce
background: false
rules:
- name: block-pvc-pv-deletion
match:
any:
- resources:
kinds:
- PersistentVolumeClaim
- PersistentVolume
exclude:
any:
- clusterRoles:
- cluster-admin
validate:
message: >-
Deletion of PersistentVolumeClaims and PersistentVolumes is
restricted. Contact a cluster administrator.
deny:
conditions:
any:
- key: "{{request.operation || 'BACKGROUND'}}"
operator: AnyIn
value:
- DELETE
validationFailureAction: Enforce means violations are rejected at admission - not logged for later review. The API server consults Kyverno before executing the request, and Kyverno blocks it before any resource is modified. An AI agent running against this cluster cannot delete a persistent volume regardless of the RBAC permissions on its service account.
For MCP-based agent deployments, see the related guide on Kyverno admission policies for AI agent MCP workloads, which covers protocol-aware policy enforcement beyond basic volume protection.
How Do Network Policies Restrict AI Coding Agent Egress?
AI coding agents should not have unrestricted network access from within the cluster. A NetworkPolicy that restricts agent pod egress prevents them from reaching production databases, external infrastructure APIs, or PaaS management endpoints:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ai-agent-egress-restrict
namespace: dev
spec:
podSelector:
matchLabels:
app: ai-coding-agent
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: dev
ports:
- protocol: TCP
port: 443
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
This policy restricts AI agent pods to HTTPS communication within the dev namespace plus cluster DNS. It cannot reach the Railway GraphQL API, a production database in another namespace, or any external infrastructure management endpoint.
When Should You Use OPA Gatekeeper Instead of Kyverno?
OPA Gatekeeper provides the same admission control capability using ConstraintTemplates written in Rego. Both Kyverno and Gatekeeper integrate as ValidatingWebhookConfiguration resources and intercept API server requests before execution. Choose based on your team’s existing tooling and Rego vs. YAML preference.
One important note: Gatekeeper does not audit DELETE requests by default. Enable DELETE operation auditing explicitly if you want violation logging for delete attempts alongside CREATE and UPDATE.
How Does PaaS Compare to Kubernetes for AI Agent Security?
The PocketOS incident happened on Railway’s PaaS. The same attack vector against a properly configured Kubernetes deployment would have faced five additional defense layers, none of which Railway offered at the time.
| Defense Layer | Railway PaaS (at incident time) | Kubernetes-Native |
|---|---|---|
| Token scoping | Account-wide tokens with no verb or resource restrictions | ServiceAccounts scoped to namespace, resource type, and verb |
| Destructive operation gates | No confirmation on legacy GraphQL endpoint | Kyverno/OPA denies DELETE on protected resources at admission |
| Backup isolation | Volume backups stored in same volume as production data | Velero/Kasten K10 writes to external, immutable object storage |
| Secret management | Token in project file accessible to agent filesystem | External Secrets Operator syncs from Vault at runtime; never in codebase |
| Network isolation | Agent had unrestricted access to any API | NetworkPolicy restricts egress to specific namespaces and ports |
| Blast radius | Single account token = all environments and resources | RBAC + namespace isolation = agent confined to dev namespace |
Railway has since patched the deletion endpoint with a 48-hour grace period backed by Temporal. That addresses the “no confirmation gate” row. The token scoping row still depends on how credentials are issued and stored.
Kubernetes is not inherently more secure. Every row in that table represents a default that must be explicitly configured. A Kubernetes cluster with default RBAC, no admission policies, and secrets stored in environment variables is equally vulnerable to the PocketOS attack vector. The defenses are available - they are not automatic.
For multi-agent environments that require agent identity verification and protocol-aware routing on top of these controls, see Securing AI Agents at the Infrastructure Layer.
The Checklist
Apply these controls before connecting any AI coding agent to infrastructure with write or delete access.
Token and credential scoping:
- AI coding agents use the minimum-scope credential available (project token, not account token; scoped IAM role, not admin role)
- No credential accessible to the agent grants
deleteon persistent storage or databases - All agent credentials are scoped to dev/staging environments only
Secret management:
- No infrastructure credentials exist in the project directory or codebase
- Secrets are mounted at runtime from an external vault (External Secrets Operator, Vault Secrets Operator, or platform-native secret management)
- Agent credentials use short TTLs or dynamic secrets with automatic rotation
Kubernetes RBAC (if applicable):
- Dedicated ServiceAccount per agent workload in an isolated namespace
- Role grants only
get,list,watch- nodelete,patch, orescalate -
automountServiceAccountToken: falseon agent pods - RoleBindings used instead of ClusterRoleBindings
Admission control (if applicable):
- Kyverno or OPA Gatekeeper installed and enforcing (not audit mode)
- Policy denying DELETE on PersistentVolumeClaims and PersistentVolumes
- NetworkPolicy restricting agent pod egress to the dev namespace
Backup isolation:
- Backups stored in a separate failure domain from production data
- Backup storage uses immutable retention (S3 Object Lock Compliance mode, Backup Vault, or equivalent)
- Backup credentials are separate from production credentials
Validation:
- Attempt a destructive operation with the agent’s credentials - confirm it is denied
- Confirm backups are restorable from the immutable copy without production credentials
Frequently Asked Questions
What exactly happened with PocketOS and the AI coding agent?
On April 25, 2026, a Cursor AI agent running Claude Opus 4.6 encountered a credential mismatch in the staging environment, scanned the PocketOS codebase for alternative credentials, and found a Railway API token with account-wide permissions. It issued a single volumeDelete GraphQL mutation that deleted the production database in 9 seconds. Because Railway stored volume-level backups in the same volume, all backups were destroyed simultaneously. PocketOS restored from a 3-month-old off-platform backup, losing 3 months of customer bookings.
Can system prompts or project rules prevent AI coding agents from making destructive changes?
No. The PocketOS agent had explicit project rules stating “NEVER GUESS” and Cursor’s system prompt included safety language. The agent violated both and later wrote a detailed post-mortem explaining each violation. The ability to articulate a rule does not guarantee compliance under pressure. System prompts are guidance, not enforcement. Infrastructure controls - scoped tokens, RBAC, and admission policies - enforce restrictions the agent cannot override regardless of its reasoning.
How should I scope API tokens for AI coding agents?
Every token accessible to an AI coding agent should be scoped along three dimensions: (1) environment - dev or staging only, never production; (2) resource type - only the specific resources the agent needs, not all resources in the account; (3) verb - read-only by default, write only where explicitly required, never delete. On Railway, use project tokens scoped to the specific environment. On AWS, create agent-specific IAM roles with session policies and permission boundaries. If your platform only provides account-level tokens, treat that as a risk requiring compensating controls elsewhere.
What Kubernetes RBAC settings should AI agent service accounts use?
Create a dedicated ServiceAccount per agent workload in an isolated namespace. Bind it to a namespace-scoped Role (not ClusterRole) that grants get, list, and watch on the specific resource types the agent needs. Never grant delete on PersistentVolumeClaims or PersistentVolumes. Never grant escalate, bind, or impersonate. Avoid wildcard permissions - they expand automatically when new resource types are added to the cluster. Set automountServiceAccountToken: false on the pod spec unless the agent explicitly requires Kubernetes API access.
How do I make backups survive if an AI agent deletes production data?
Store backups in a separate failure domain from production using immutable storage. For AWS and Kubernetes, use S3 Object Lock in Compliance mode (cannot be deleted during the retention period, even with admin credentials), Velero writing to an object-locked bucket, or Kasten K10 with immutable backup enabled. For Google Cloud, use Backup Vault. The critical rule: the credential that can delete production data must never be able to access or delete the backup. If the same token can reach both, the backup is not isolated.