Lakshmi Narasimhan
ESSAY

I Found a Cryptominer in My Client's Production Cluster. Claude Code Found the Attacker.

New Year’s Day. Coffee in hand. Ready to ease back into work.

Then I saw the logs.

2026-01-02T06:34:27 GET xmrig-6.24.0-linux-static-x64.tar.gz
2026-01-02T06:34:30 GET http://37.32.6.33:7979/m
2026-01-02T06:34:30 spawn /opt/systemf/m ENOENT

xmrig. In production. Someone was mining Monero on my client’s Kubernetes cluster.

The horror.

The Investigation

I had a few hundred megabytes of JSON logs and approximately zero patience for manually correlating timestamps. So I did what any reasonable person would do: I asked Claude Code to analyze the logs and figure out what triggered the miner download.

Within seconds, it built a timeline:

Time Event

06:34:26. Normal request to /onboarding

06:34:27. xmrig downloaded from GitHub

06:34:30. Secondary payload from sketchy IP

06:34:57. Container OOMKilled

The cryptominer was so resource-hungry it consumed 2GB of memory in 30 seconds and crashed the container. Ironic. The attacker’s greed saved us from a prolonged compromise.

But how did they get in?

Chasing Red Herrings

Claude Code’s first suspect: a low-version npm package called device-unique-keygen. Added by a developer whose email matched the package maintainer. Classic supply chain attack pattern.

I got excited. Maybe too excited.

Claude Code fetched the GitHub repo, analyzed the source code, checked for postinstall scripts, looked for obfuscated code, searched for eval() calls.

Nothing. The package was clean. Just a browser fingerprinting library. Boring. Legitimate.

We moved on.

No malicious init containers. No sidecars. No .ashrc shenanigans. The Dockerfile was clean. The pod spec was clean.

Everything was clean except someone was definitely mining crypto on our infrastructure.

The Actual Answer

Claude Code ran npm audit on the codebase.

critical │ Next.js is vulnerable to RCE in React flight protocol
Package  │ next
Patched  │ >=15.3.6
Your ver │ 15.3.4
CVSS     │ 10.0

CVSS 10. The maximum possible score. The “your house is actively on fire” of security ratings.

The app was running Next.js 15.3.4. A publicly disclosed RCE vulnerability. No authentication required. An attacker could run arbitrary commands on the server by sending a crafted request.

That’s exactly what happened. They sent a request, ran wget twice, downloaded the miner, and started extracting crypto value from compute cycles they weren’t paying for.

The container’s memory limit stopped them. A $20/month Kubernetes resource limit prevented what could have been ongoing theft.

What Claude Code Actually Did

I want to be clear about what happened here. I didn’t single-handedly unravel a sophisticated attack. I didn’t manually correlate log timestamps or reverse-engineer obfuscated npm packages.

I said “check these logs” and Claude Code:

  • Built a timeline from JSON log entries

  • Identified the malware artifacts and C2 server

  • Traced git blame to find who added suspicious packages

  • Fetched and analyzed source code from GitHub

  • Ruled out attack vectors one by one

  • Found the actual vulnerability via npm audit

  • Correlated the OOMKill timing with the attack

  • Suggested remediation and forensic preservation steps

The entire investigation took under an hour. Not because I’m fast. Because Claude Code is.

The Fix

pnpm update next@^15.3.6

One command. That’s the remediation for a CVSS 10.0 vulnerability.

We also orphaned the compromised pods for forensic analysis, rotated secrets, and added proper security contexts to prevent future wget adventures.

The Lesson

Two things saved us:

  1. Centralized logging (couldn’t investigate without the logs)

  2. Memory limits (the attacker’s miner killed itself)

One thing would have prevented this entirely: running npm audit before deployment.

The attacker exploited a vulnerability that was publicly disclosed and patched. We just hadn’t updated yet.

Godspeed with your own dependency updates.


My Medium friends can read this over there as well.