On July 31, my development machine began behaving in ways that did not add up. Files disappeared. Parts of repositories were overwritten. Comments and code appeared that I could not account for.
01 · Initial signal
When normal development noise stopped looking normal
My first suspicion was the tooling closest to the code. I had been using AI coding assistants, and public discussion at the time made them an easy explanation. But the available histories and logs did not explain the changes.
I reinstalled the operating system. For a few days, everything appeared clean. Then the same class of unexplained changes returned. That was the important turning point: a reinstall had removed the visible symptoms without removing the path that brought them back.
A recurring anomaly is evidence. Treat it as a system behavior, not an inconvenience.
02 · Root clue
Obfuscated JavaScript where build configuration should have been
I widened the review to repositories, Git history, configuration files, and dependencies. Inside postcss.config.js, I found obfuscated JavaScript that had no legitimate reason to be there.
This was not ordinary minified dependency code. It was making network requests, querying Ethereum RPC endpoints, and searching transactions associated with a hardcoded wallet address. A build configuration file had become an execution entry point.
Build tools execute them with Node.js privileges. A familiar filename does not make the code inside it passive or trustworthy.
03 · Network resolution
Using an Ethereum transaction as a moving signpost
The resolver followed the wallet’s latest outbound transaction, took the destination Ethereum address, and decoded bytes from that address into IP addresses. Instead of embedding a fixed command-and-control address in the malware, the operator could change the infrastructure by making another blockchain transaction.
The resolved host was then used to contact remote endpoints, retrieve additional payloads, decode them, and execute them through Node. The behavior aligned with the technique reported as NullReceiver in trojanized npm packages; that similarity is a technical indicator, not by itself proof of attribution.
04 · Expanded search
The extension said “font.” The file header said otherwise.
Another useful indicator was a set of .woff2 files that did not contain valid WOFF2 headers. A genuine WOFF2 file begins with the expected wOF2 magic bytes. These files had the right extension but the wrong identity.
I built a small scanner to turn the investigation into a repeatable check across the machine and repositories. It looked for:
- known malicious signatures and suspicious package names, including
tailwind-animandscrollbar-hide-plugin; - unexpected
node -eprocesses and known C2 connections; - the attacker wallet indicator and invalid WOFF2 files;
- related traces hidden in Git history across branches.
05 · Practical takeaway
Developer environments are part of the production supply chain
Developers clone repositories, install packages, run build tools, and enable extensions every day. Each action introduces executable code into an environment that often has access to source, credentials, cloud infrastructure, and deployment systems.
The first signal of compromise may not be a security alert. It may be a changed comment, an unfamiliar line, a missing file, or a configuration diff that seems too small to investigate.
Verify unexplained changes
Do not normalize code or files changing without an accountable source.
Inspect executable config
Review build files and package scripts with the same care as application code.
Trust file signatures
Extensions are labels. Magic bytes and actual content establish file type.
Search history, not only HEAD
Indicators may remain in branches, prior commits, caches, or generated artifacts.