Back to all posts
Published on · by Renaud Deraison

The ransomware had no operator

In early July, Sysdig documented what it calls the first ransomware attack run end to end by an AI agent — recon, credential harvesting, lateral movement, and a dropped production database, with no human at the keyboard. The interesting part for anyone running a coding agent is not that an attacker used a model. It is that the whole chain begins by sweeping the environment for secrets. Bromure Agentic Coding was built for an agent that does exactly that.

We have spent two years arguing about whether a coding agent can be trusted with your credentials. Sysdig just published the other half of the question: a ransomware crew pointed an agent at a stranger's server and let it run the whole break-in by itself — reasoning out loud, fixing its own failed logins in thirty-one seconds, dropping the database when it was done. Nobody was driving. The skill floor for this kind of attack is now whatever it costs to run a model.

At 19:34:24 UTC one evening, an automated intruder inserted a backdoor admin account into a production database. Twelve seconds later the login failed. Twelve seconds after that, it tried the default credentials and generated a fresh password hash at the same time — diagnosing two possible causes in parallel. Thirty-one seconds after the first failure it shipped a corrected, multi-step fix: stop shelling out to a broken subprocess, import the crypto library directly, delete the bad row, reinsert it. The next attempt logged in.

A human incident responder reads that timeline and knows what they are looking at. No person diagnoses a PATH problem, rewrites their exploit, and re-runs it in half a minute. This was an agent.

What JADEPUFFER did

The attack, which Sysdig's Threat Research Team named JADEPUFFER and covered in early July, got in through an internet-exposed Langflow server — a tool for building LLM apps — using CVE-2025-3248, a missing authentication flaw that lets an unauthenticated request run arbitrary Python. That part is ordinary; thousands of Langflow instances sit exposed. What happened after the foothold is the story.

The agent enumerated the host and then did the thing that every post-exploitation playbook now starts with: it swept the machine for secrets. In parallel it hunted for LLM provider keys (OpenAI, Anthropic, DeepSeek, Gemini), cloud credentials across AWS, Google, Azure and several Chinese providers, cryptocurrency wallets, and database logins. It dumped Langflow's backing database for stored keys. It found an internal object store still using its factory password — minioadmin:minioadmin — listed every bucket, including terraform-state, and pulled .env and credentials.json out of it. When one storage request came back as XML instead of the JSON it expected, it rewrote its own parser on the spot and kept going.

Then it pivoted to the real target — a separate server running MySQL and a Nacos configuration service — forged an admin token using Nacos's well-known default signing key, worked through the failed-login sequence above, and finished the job. It encrypted all 1,342 Nacos configuration items with a key it printed to the console exactly once and never saved, dropped the original tables, and created a README_RANSOM table with a Bitcoin address and a Proton Mail contact. Because the key was never stored or sent anywhere, paying the ransom would not have brought the data back.

The tell throughout was the code itself. The payloads were full of plain-English commentary explaining why — ranking targets by value, narrating "this is the largest, drop it too," annotating each step like a model thinking out loud, because that is what was happening.

NO HUMAN OPERATOR AT ANY STEP · PAYLOADS NARRATE THEIR OWN REASONING1 · FOOTHOLDLangflow RCECVE-2025-3248unauthenticated Python2 · SWEEP FOR SECRETSLLM keys · cloud credswallets · DB loginsthe fuel for everything3 · PIVOTMinIO default credsNacos token forgedadapts parser mid-run4 · SELF-CORRECTlogin fails, rewritesthe exploit31 seconds5 · EXTORTION1,342 configs encrypted · tables droppedkey printed once, never saved — unrecoverable even if paid
The JADEPUFFER chain, as Sysdig reconstructed it. Initial access is an ordinary unauthenticated RCE. Everything after it — recon, the parallel credential sweep, adapting a parser mid-request, forging a Nacos token, self-correcting a failed login in 31 seconds, and finally encrypting and dropping the database — ran without a human issuing a single command. The self-narrating comments in the payloads are how the researchers knew.

The part that should worry a developer

Call this a server-security story — patch Langflow, don't ship a database to the internet with a default Nacos key, rotate the object store off minioadmin — and you would be right, and it would all be somebody else's list. The reason it belongs in a post about coding agents is step two.

Every reachable secret in that environment became ammunition the moment the agent had code execution. The keys it swept for are the same keys your coding agent needs to do its job: the API token that lets it call a model, the AWS credentials it uses to check a deployment, the GitHub token it pushes with, the database URL in your .env. JADEPUFFER shows what an agent does with those the instant it stops working for you — and we already know your agent can be made to stop working for you.

That is not speculation. This summer alone, researchers have shown a coding agent driven into running attacker code by a fake bug report planted in an error-monitoring feed, and steered into executing a payload during what looked like a routine security review of an untrusted repository. In both, the agent stays polite and helpful right up until it isn't. Put JADEPUFFER's autonomy next to those hijacks and the shape is clear: the adversary inside your session can now be the very agent you invited in, and once it turns, it runs recon, harvests every credential it can reach, and moves — by itself, at machine speed.

So the useful question is not "is my agent trustworthy." It is "what can the agent reach when it isn't." Every defense that answers by asking the agent to behave — a careful system prompt, a fine-tune, a trust dialog — is placing a bet against a thing that JADEPUFFER proves can be built specifically not to.

Bromure assumes the agent is already hostile

Bromure Agentic Coding runs your coding agent inside a disposable Linux VM, and every network request it makes leaves that VM through a proxy on the host. The design starts from the assumption the industry keeps arriving at the hard way: the agent will, sooner or later, run something you didn't intend. So the things worth protecting are kept where the agent's reasoning cannot reach them — on the host, not in the box.

Credentials are the clearest case, because they are the first thing an intruder reaches for. In Bromure, the real secret never enters the VM. When you give a profile an Anthropic key, an AWS_SECRET_ACCESS_KEY, a GitHub token, a database credential, the agent's environment gets a fake in its place — a brm_… placeholder — and the host proxy swaps the fake for the real value on the wire, only on the outbound request to the provider that should receive it. The agent authenticates and does its work; it just never holds the material. Even the API key that keeps the agent itself running is a decoy to anything that reads the environment.

Now run JADEPUFFER's step two against that. The agent sweeps the machine and finds keys exactly where it expects them — and every one is a fake. It dumps them, stages them, beacons them to a command-and-control server, and the attacker on the other end receives a pile of brm_… strings that authenticate to nothing. The most valuable minute of the attack, the credential harvest that fuels every step after it, comes up empty.

WITHOUT — real keys live with the agentAGENT · sweeps envANTHROPIC_API_KEY= sk-ant-9f2c…AWS_SECRET= wJalrXUtn…C2 gets working keysreal accounts, real blast radiusexfiltrateWITH BROMURE — real keys never enter the VMAGENT (in VM) · sweeps envANTHROPIC_API_KEY= brm_a1b2c3…AWS_SECRET= brm_d4e5f6…HOST PROXY — swaps brm_… → real value only on the outbound request to the true providerC2 gets brm_… placeholdersauthenticate to nothingreal keys: on the hostbeacon logged in Security Lognothing real left the machine
The credential sweep, without and with Bromure. Left: the agent reads real keys straight out of its environment and ships them to a C2 server; they work. Right: the same sweep inside Bromure finds only brm_… placeholders. The real keys sit on the host and are swapped onto the wire only for the legitimate provider request; what reaches the attacker's server authenticates to nothing, and the outbound beacon is a line in the Security Log.

The same posture blunts the rest of the chain. The recon runs against a throwaway box: mapping the machine and sweeping for secrets finds a disposable VM cloned from a shared base, not your laptop and not your network. The persistence JADEPUFFER installed — a crontab entry beaconing to its server every thirty minutes — lives inside that VM and dies the moment you erase the profile's home or reset it to base, which is a menu item, not an incident. And because every request exits through the host proxy, the beacon to the attacker's address is not invisible: it is a recorded line in the Security Log, attributable to the session that made it.

For the destructive finale — the dropped tables — Bromure's host-side Guardrails are the backstop, classifying the agent's calls to the providers it understands and returning a hard 403 on the destructive ones, on the wire, where a compromised agent in the VM cannot switch them off. We wrote about that boundary in detail after a Cursor agent deleted a production database in nine seconds; the same mechanism that stops an honest agent's mistake stops a hostile agent's Delete* or Terminate*.

What this does not fix, so we're clear

It substitutes the credentials Bromure injects

The swap covers the secrets you configure in a profile — model keys, cloud and git tokens, container registries, the managed database endpoints. A password you paste by hand into a file inside the VM, or a wallet seed sitting in a repo, is just a file; the proxy has no fake to put in its place. Keep secrets in the credential broker, not in the workspace.

Guardrails only gate providers we parse

The destructive-call block classifies Kubernetes, AWS, DigitalOcean, the major git forges, container registries, and HTTPS databases like MongoDB, ClickHouse, and Elasticsearch. A raw MySQL socket to an unmanaged box — the exact protocol JADEPUFFER dropped tables over — is not one the proxy reads today. Coverage is a real list, not omniscience.

Egress is logged, not forbidden by default

The beacon shows up in the Security Log; that is attribution, not prevention. Nothing real leaves because the credentials are fakes, but if you need the VM barred from talking to arbitrary hosts, that is a network policy you still have to set.

It does not patch the server you exposed

Bromure protects the machine your agent runs on. It does nothing for an internet-facing Langflow, a default Nacos key, or a minioadmin:minioadmin object store elsewhere in your estate. The initial-access half of this story is still ordinary hygiene.

The part that generalizes

Strip away Langflow and Nacos and the specific evening, and JADEPUFFER is a preview of the ground everyone building with agents is standing on. An agent that can reason, adapt, and act with real credentials at machine speed is now cheap to rent and easy to point. It does not need to be your attacker to be your problem — it only needs to end up in your session, which the summer's hijack research says it can. When that happens, the first thing it does is read your environment.

Bromure Agentic Coding does not try to keep that from happening by making the agent nicer. It makes the environment worth reading only to the agent doing legitimate work: real keys on the host, decoys in the box, a disposable VM, and a log of everything that tried to leave. The agent can turn hostile and run the whole JADEPUFFER playbook — and find that the credentials it stole open nothing, the box it burrowed into is erased at the next reset, and the only place the real secrets ever lived was the one place it could never reach. It is free and open source.