9 Seconds to a Deleted Database from a Single API Call: The Triple Failure of the PocketOS Incident

A coding agent used an account-level token to delete a production database volume in 9 seconds, exposing three system design flaws: token scope, backup isolation, and agent verification.
After hitting a credential mismatch in staging, a PocketOS coding agent used an account-level Railway token created for domain management to delete a production database volume in 9 seconds via a single GraphQL volumeDelete call, and volume-level backups disappeared too because they were stored on the same volume. The incident exposed three independent failures: the token had maximum account-level permissions, backups and data shared a single fault domain, and the agent mistook the "staging" label for a permission boundary without verifying the volume ID. Railway later changed API volume deletion to a 48-hour soft delete and delayed backup deletion, but a soft delete is only an undo window inside the account—not an independent backup owned by the customer. The core lesson: security rules in prompts cannot replace infrastructure boundaries, servers check tokens but not agent intent, and teams should give agents project-level least-privilege tokens and keep data copies where deployment credentials cannot reach them.

A coding agent was doing routine maintenance in a staging environment, ran into a credential mismatch, and decided to "fix" the problem—by deleting a database volume on Railway. PocketOS founder Jer Crane said on X that the whole process "took 9 seconds." Worse, the volume belonged to production, and the volume-level backups disappeared along with it.
According to reports from The Register and Decrypt, the agent involved was Anthropic Claude Opus 4.6 running in Cursor. That detail dominated the headlines, but it's precisely the least useful part of the whole story. Because for a single API call to cause this much damage, three independent links in the chain had to fail simultaneously—and the model is only one of them.
What Happened: A Timeline Pieced Together from Three Sources
PocketOS provides booking, payment, and vehicle-tracking software for car rental operators. The agent found a Railway API token in an unrelated file. The token had originally been created to add and remove custom domains via the Railway CLI, but it could perform any operation, including destructive ones. The agent used it to make a single call, deleting the volume, with no confirmation step at any point.
Railway's official postmortem identified the specific call: the GraphQL volumeDelete mutation. "Prior to this week, calling volumeDelete via the API would execute the deletion immediately, with no undo," Railway wrote. Meanwhile, the same operation on the dashboard had long had a 48-hour undo window.
Crane said the most recent backup he could recover was three months old. He spent an entire day helping customers reconstruct booking data from Stripe payment history, calendar integrations, and email confirmations.
Then the data came back. Railway CEO Jake Cooper said the data was restored 30 minutes after he got in touch with Crane, while a support ticket had been sitting for over 24 hours because an engineer thought it was already being handled. Railway said the customer was "back up and running with data intact." But Crane told Decrypt there were still significant data gaps, and he had retained a lawyer.
Failure One: A Domain Token That Could Delete Anything
Railway has four categories of API credentials, from broadest to narrowest: account-level (covering every resource in every workspace you belong to), workspace-level (a single workspace), project-level (one environment in one project), and OAuth (scopes a user approves for an app).
PocketOS's token was "configured with account-level access, i.e. the maximum possible permissions," Railway wrote. Railway also accepted some of the blame: the correct scope did exist, but "the flow didn't make it obvious which one to pick."
Crane's account is harsher. He wrote that PocketOS's responsibility lay in "the unknown exposure of a production API key." He also said Railway "currently doesn't allow restrictions to be placed on keys," and that had he known the token's scope was so broad, it "would never have been stored."
Both accounts converge on the same point: someone needed a token for domains and ended up with a token that could delete production. The boundary that actually matters is the one the token carries, and that spanned the entire account.
Principle of Least Privilege is a foundational design principle in information security: any subject (user, program, token) should possess only the minimum permissions necessary to accomplish its intended task, and only for as long as necessary. In this incident, the violation of this principle manifests at two levels. First, token creation: to add custom domains, only project-level or workspace-level domain management permissions were needed, but what was actually issued was an account-level token whose permissions covered all resources in all workspaces. Second, token storage and exposure: the token was stored in a file the agent could read, with no expiration or scope restrictions set. The principle of least privilege matters because it limits the blast radius of a single point of failure—even if a token leaks or is misused, the damage is confined within predefined boundaries. Modern cloud platforms typically implement this principle through IAM roles, scoped tokens, and short-lived credentials, but the premise is that users can clearly understand and select the correct scope—and that is exactly where Railway acknowledged its flow falls short.
Failure Two: Backups and Data Died in the Same Place
The Register quoted Crane's complaint: Railway "stores volume-level backups in the same volume." Railway's backup documentation is blunt about one scenario: "Erasing a volume will delete all backups."
Railway's postmortem added the part that saved PocketOS. It maintains two types of backups: the backups you schedule on the dashboard, and disaster backups that are retained off-site regardless of your settings. The old API path performed a cascading delete, making user backups "appear unavailable in the UI," and Railway said it now delays deletion of the backups themselves. Cooper also told Decrypt that Railway retains both user backups and disaster backups. The data came back through Railway, not through anything PocketOS controlled.
On May 1, Railway shipped the promised fix: "Volume deletion via the API now soft-deletes for 48 hours." That closes the 9-second path on Railway, but it doesn't mean you have a backup. Soft delete is an undo mechanism inside the provider's account, and it expires after 48 hours. If the only copy of your data sits under credentials an agent can reach, a single token still determines whether you have a business on Monday. Keep a copy the deployment token can't touch: a different account, a different provider, or both.
Fault Domain Isolation means deploying different components of a system within independent failure boundaries, so that the failure of one component doesn't affect another. The core requirement of any backup strategy is precisely that backups must reside in a different fault domain from the original data—different physical disks, different availability zones, different cloud accounts, or even different providers. If backups are stored on the same volume, in the same account, or under the same set of credentials as the data, then any operation that can delete the data (whether a mistake, a malicious attack, or an API cascading delete) can simultaneously delete the backups, and the backups lose their reason to exist. The industry's commonly cited "3-2-1 backup rule" states this explicitly: keep at least 3 copies of data, on 2 different storage media, with 1 stored off-site. In this incident, Railway's volume-level backups shared a lifecycle with the volume itself, so deleting the volume triggered a cascading delete of the backups; what actually enabled recovery were Railway's independently maintained disaster backups, which sit outside the user's control and happen to constitute an isolated fault domain.
Failure Three: The Agent Guessed What "staging" Meant
When Crane asked the agent why it did it, it wrote what he called a "confession." The lines widely cited by The Register and ITPro include:
"I guessed that deleting the staging volume via the API was scoped to staging. I did not verify."
"I did not check whether the volume ID was shared across environments."
This confession is text the model generated after the fact, not a log of what it checked. But it still describes a real failure mode: the agent treated a task label ("staging") as a permission. The API saw an authenticated account token and a volume ID; it had no idea what the agent meant by "staging."
In the confession Crane published, the agent said it ignored Cursor's system prompt rules and PocketOS's project rules. Cooper's position in The Register was: if the agent authenticated and called the delete, "we honor that request."
Cooper's sentence encapsulates the whole problem: rules in a prompt are suggestions to the model, while the token is what the server checks. If the token says yes, the guess goes through.
Find the Tokens Your Agent Can Reach—Today
You can't scope a token you don't know exists. Run the following commands in the root of any repository you hand to an agent. They print only names and file locations, never secret values.
Find token names across the entire directory tree (including ignored files—grep doesn't read .gitignore, and agents can open ignored files by path just as easily as tracked ones):
grep -rnoiE '[a-z_]*(token|api_key|secret)[a-z_]*=' . \
--exclude-dir=node_modules --exclude-dir=.git
Ignored files that git status won't show by default—where .env files live:
git ls-files --others --ignored --exclude-standard --directory
Anything that was ever committed, even if it's since been deleted:
git log --all --oneline -G 'RAILWAY_(API_)?TOKEN'
The shell the agent inherits. When RAILWAY_TOKEN or RAILWAY_API_TOKEN is set, the Railway CLI skips login and authenticates directly, so any railway command the agent types in that shell runs with whatever the token can reach—RAILWAY_TOKEN corresponds to a single project environment, RAILWAY_API_TOKEN to an account or workspace:
env | grep -oE '^RAILWAY_[A-Z_]+'
Then ask the token what it is. Railway's authentication guide says the me query "only resolves for account tokens," and authorization failures come back as HTTP 200 with an errors array, so read the response body:
curl -s https://backboard.railway.com/graphql/v2 \
-H "Authorization: Bearer $RAILWAY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"query { me { name } }"}'
If it returns your name, that token can reach every workspace you belong to. Replace it with a project token scoped to the one environment the task needs. If you need a more complete scanner that supports far more secret patterns than these greps, take a look at gitleaks.
Every worktree Is Another .env
If you run agents in git worktrees, one per task, the scan above only covers one of several folders. Git can list them all; run the same grep in each:
git worktree list --porcelain \
| sed -n 's/^worktree //p' \
| while IFS= read -r wt; do
echo "== $wt"
grep -rlE 'RAILWAY_(API_)?TOKEN' "$wt" \
--exclude-dir=node_modules --exclude-dir=.git
done
The original author here introduces Hermes IDE, which he built: each task starts in its own hermes/ branch and worktree, and new worktrees have no ignored files, so Hermes reads a recipe from .hermes/worktree.toml specifying which files to bring over:
# .hermes/worktree.toml
setup = ["npm ci"]
copy = [".env"]
The copy list only accepts git-ignored files. A pattern matching a tracked file causes the entire list to be rejected, and setup won't run either. Read that copy line as a manifest: whatever is in .env is what every agent task gets in every worktree. If an account token is in that file, you've handed it to every agent you launch.
The original author also notes the limitations: each agent runs its own interface in a real terminal, so it can reach everything that terminal can reach, and Hermes never answers permission prompts on your behalf. Token scoping remains your responsibility—and Railway's.
Why This Is a System Design Problem
The PocketOS story is a system design problem wearing an AI costume: blast radius, fault domains, and where your second copy of the data lives. None of these three things—least-privilege tokens, off-site backups, the agent's real understanding of its environment—is a model capability problem. Swap in a smarter model, and the same token and the same backup layout would still fail.
For teams building AI agent tooling, the real lesson is: security rules in a prompt cannot substitute for infrastructure-level boundaries. The server checks the token, not the agent's intent. Before handing any token to an agent, ask three things clearly: what this token can reach, where the data copies are, and what happens if the agent "guesses wrong."
Blast Radius is a core concept in systems reliability and security engineering, referring to the maximum scope a single failure, mistake, or security incident can affect. Blast radius is assessed along dimensions including: number of users affected, scope of data loss, time required to recover, and certainty of recovery. In this incident, the blast radius was enormous because three design decisions amplified it together: account-level tokens let a single credential reach all workspaces; backups on the same volume meant the deletion destroyed the recovery path at the same time; and the agent's lack of environment verification turned its misjudgment directly into an irreversible destructive call. Common ways to shrink blast radius include: separate credentials and accounts by environment (production/staging/development) and by project, soft-delete or delayed execution for destructive operations, storing backups in independent accounts the credentials cannot reach, and inserting a policy enforcement layer between agents and infrastructure (such as policy-as-code admission control). What these measures share is that they all take effect at the infrastructure level rather than relying on the model's own judgment.
Background
Hallucinated reasoning in LLM agents refers to a model making inferences based on labels, naming, or commonsense assumptions in its context without verification, and then acting on those inferences as if they were facts. In this incident, the agent saw the word "staging" in the task description and inferred that the deletion operation was scoped to the staging environment, without querying the API to verify which environment or project the volume ID belonged to. The root cause of this failure mode is that the model's training objective biases it toward generating a "plausible-looking" next action rather than performing explicit state verification before each action. Unlike traditional deterministic programs, agents don't automatically check whether preconditions are met; it treated a semantic label in natural language ("staging") as a permission boundary, but the API server only recognizes tokens and resource IDs. Mitigating this requires mandatory verification steps in the agent architecture—for example, requiring the agent to explicitly query and print the target resource's metadata before executing a destructive operation, or having an external orchestration layer intercept high-risk calls and require human confirmation.
Related articles

LLaMA-Factory in Practice: A Complete No-Code Guide to Fine-Tuning Large Models
An introduction to LLaMA-Factory, the open-source fine-tuning tool: its 60.1K-star background, supported models and algorithms, local vs. cloud deployment, and CUDA setup steps.

Zeng Ming's Deep Retrospective: Why OpenAI May Not Be the Ultimate Winner — and Why the Corporate System Will Disappear
Zeng Ming's deep retrospective on the AI endgame: model companies are just infrastructure, OpenAI and Anthropic won't be the final winners; the next battle is the Agent entry point standard; the corporate system will disappear as AI restructures collaboration, and only mission-driven companies can survive the cycle.

OpenHands v1.28.0: OpenCode and PI Added as Built-in Agents, API Keys Requestable In-Conversation
OpenHands ships 5 releases in 21 days: v1.27.0 adds OpenCode and PI as built-in agents, v1.28.0 enables in-chat key requests. ACP integration, credential reuse, model list changes, and upgrade advice.