RC RANDOM CHAOS

A reverse shell dressed as a Firefox patch

Inside the 2025 AUR compromise: how CHAOS RAT shipped in fake browser packages, why update automation made it worse, and how to audit PKGBUILDs in 30 seconds.

· 8 min read

On July 16, 2025, an AUR account named danikpapas uploaded three packages to the Arch User Repository: librewolf-fix-bin, firefox-patch-bin, and zen-browser-patched-bin. Each one pulled a “patch” from a GitHub repository during the build step. The patch was CHAOS RAT - an open-source remote access trojan written in Go that hands an attacker a reverse shell, file upload and download, and credential theft. The packages sat live for roughly 48 hours before the Arch team removed them on July 18. Nobody knows how many machines built them in that window, because the AUR doesn’t track installs. That last sentence is the most important one in this post.

A trust model that failed exactly as documented

The AUR is not a software repository. It’s a repository of build recipes - PKGBUILDs - that anyone with a free account can publish. There is no review queue, no code signing by a central authority, no vetting. The Arch wiki says this plainly: you are expected to read the PKGBUILD and verify what it does before you build it. That’s the entire security model. It’s a social contract, not a technical control.

So when people call this a “vulnerability in the package manager,” they’re misdiagnosing it. Pacman wasn’t exploited. The AUR wasn’t breached. An attacker used the system precisely as designed: create account, upload package, wait. The failure happened in the gap between the documented trust model (humans read PKGBUILDs) and actual user behavior (helper tools, —noconfirm flags, unattended update scripts). That gap is where almost every supply chain incident lives, on every platform. The AUR just makes it unusually visible.

What the packages actually did

The mechanics are worth walking through because they’re boring, and boring is the point - nothing here required sophistication.

A PKGBUILD declares a source array: the files fetched before the build runs. These three packages listed a Git repository, github.com/danikpapas/zenbrowser-patch, alongside the legitimate browser sources. During the build, that “patch” delivered the CHAOS RAT payload. The implant installed itself with a name chosen to blend in - the running executable showed up at /tmp/systemd-initd, a string engineered to look like systemd plumbing to anyone skimming a process list. Persistence came through a systemd service, so the implant survived reboots.

Once running, it connected to a command-and-control server at 130.162.225.47 on port 8080 - a bare IP on a cloud host, no domain fronting, no encryption theater. CHAOS RAT’s feature list covers the standard kit: remote shell, file exfiltration, screenshots, system reconnaissance. The infostealer label fits - browser credentials, session cookies, SSH keys, anything readable by the user who ran the build is in scope.

The package names did targeting work the malware didn’t have to. “firefox-patch-bin” and “librewolf-fix-bin” are names built for people searching the AUR for a fix to a current annoyance. A user looking for a patched browser is in a hurry, and a user in a hurry doesn’t read 80 lines of bash.

”Rootkit” is the wrong word, and the right word matters

Some of the coverage attached “rootkit” to this incident. The artifact doesn’t support that. A rootkit hides - from the kernel, from process listings, from file enumeration. CHAOS RAT does none of this. It’s a user-space implant relying on name camouflage: a process called systemd-initd, a service unit that looks plausible in a long systemctl listing.

This isn’t pedantry; it dictates your detection strategy. A name-masquerading user-space RAT is visible to every standard tool. ss -tupn shows its outbound connection. systemctl list-unit-files shows its persistence. ls /tmp shows its binary. You can find this thing in five minutes with utilities already on your system. A kernel-mode rootkit defeats all of those, and finding it means offline disk analysis or memory forensics.

Calling everything a rootkit trains people to believe detection is hopeless without specialist tooling. For this class of malware, the opposite is true. The attacker bet that nobody would look. On most single-user Arch boxes with no monitoring in place, that’s a good bet.

Automation turned one bad upload into a fleet problem

The AUR’s social contract assumed a human in the loop. AUR helpers quietly removed that human.

yay and paru both display PKGBUILD diffs before building - paru does it by default, yay prompts. But both accept —noconfirm, and a meaningful slice of users run exactly that, nightly, in a script or a systemd timer, because manual review is friction and friction loses to convenience over time. For those users, the review step the entire trust model rests on executed zero times.

This is the same dynamic that makes npm postinstall scripts and PyPI typosquats profitable: the package layer assumes review, the automation layer skips it, and the attacker only has to slip into the queue. Unattended upgrades are correct for the official Arch repositories - those packages are signed and maintained by a vetted team. Applying the same automation posture to the AUR is a category error: it treats user-submitted bash from anonymous accounts as if it carried the trust level of the signed core repos. The tooling shows both kinds of package side by side, which makes the error easy to commit.

Within days of the takedown, copycat packages carrying the same RAT appeared under new names and fresh accounts. The AUR team removed those faster - but the playbook costs an attacker nothing to rerun.

Forty-eight hours, and nobody knows the blast radius

The timeline: uploaded July 16, flagged by community members who noticed the suspicious GitHub repository and ran the payload through VirusTotal, removed by the Arch team on July 18. Arch’s announcement was terse - remove the packages, take the necessary measures to ensure you weren’t compromised.

Two systems observations. First, detection was community vigilance - a user reading something they weren’t required to read. There’s no scanner, no telemetry, no behavioral analysis sitting in front of the AUR. The control that worked was a volunteer with good instincts and a free afternoon. That control doesn’t scale and doesn’t repeat reliably.

Second, the blast radius is unmeasurable by design. The AUR records votes and popularity but doesn’t track downloads or installs. Nobody - not Arch, not the researchers who analyzed the payload - can state how many machines executed that PKGBUILD. Compare crates.io or npm, where download counts at least bound the exposure estimate. When your distribution channel has no install telemetry, every incident response starts with “we don’t know who’s affected” and ends with hoping the affected users read the news page.

Auditing PKGBUILDs without making it a second job

The fix isn’t “read every line of every PKGBUILD forever.” It’s a short checklist applied at the moments that matter.

Read the diff, not the file. paru shows PKGBUILD diffs on update by default; leave that on. A diff on an update is usually a few lines - a version bump and a checksum. New URLs in the source array, new lines in build() or package(), checksums set to SKIP on remote sources, or a new .install file are the red flags. The malicious packages here would have shown a personal GitHub repo in the sources. That’s a thirty-second read.

Profile the package before first install. First-submitted date, maintainer account age, vote count, comments. firefox-patch-bin was days old, from a new account, with no votes, claiming to fix one of the most-used programs on the platform. That profile is the whole story - no code reading required.

Scope your automation. Unattended updates for official repos: fine, they’re signed. AUR updates: interactive only. If you genuinely need automated AUR rebuilds, build in a clean chroot (devtools or aurutils) and diff each PKGBUILD against the last version you reviewed, failing the build on unreviewed changes.

Watch egress. Every RAT phones home. OpenSnitch gives you per-application outbound prompts on a workstation. Even without it, a periodic ss -tupn review catches a persistent connection to a bare IP on port 8080. This is the control that catches the implant you missed at install time - a second layer for a threat model where the first layer is “I was in a hurry.”

If you installed one of these

Removing the package with pacman -Rns does not remove the implant - the payload installed itself outside pacman’s file tracking.

Check for the binary at /tmp/systemd-initd and the process in ps output. Audit systemd units with systemctl list-unit-files, and don’t skip the user-level units under ~/.config/systemd/user. Kill the process, remove the unit, remove the binary.

Then assume the credential theft succeeded. Rotate passwords, SSH keys, and API tokens readable from that account. Invalidate browser sessions everywhere - stolen session cookies bypass two-factor authentication entirely, and CHAOS-class tooling collects them.

The honest recommendation for a confirmed infection is harsher: a RAT with shell access means an attacker may have changed anything your user could write, and you can’t enumerate that after the fact. Reinstall, restore data from backups taken before July 16, rotate everything. It’s a day of work against an unbounded tail risk.

The same shape, everywhere else

Strip the Arch specifics and the pattern generalizes: a low-friction publishing layer (AUR, PPAs, COPR, Homebrew taps, npm, PyPI, VS Code extensions), a naming lure (typosquats, “-fix” and “-patched” variants), and automation that installs without human review. Every ecosystem that bolts convenience onto an open contribution model recreates this incident eventually, and most already have.

The AUR’s defense is that it never claimed to be trusted - the documentation says so on every relevant page. The systems failure is that tooling defaults and user habit quietly upgraded its perceived trust level to match the official repos. Wherever you find a convenience layer that removed a human from an install path, that’s the audit point: add back a compensating control - diff review, chroot isolation, egress monitoring - or accept that you’ve delegated code execution on your machine to whoever registers the right package name first.

See also: NordVPN for tunneled traffic when operating outside controlled networks.


#ad Contains an affiliate link.

Share

Keep Reading

Stay in the loop

New writing delivered when it's ready. No schedule, no spam.