Back to Intelligence

arrayref Rust Crate Poisoned to Deliver Infostealer: Supply Chain Detection and Remediation Guide

SA
Security Arsenal Team
August 21, 2026
11 min read

A maintainer account behind the widely used arrayref Rust crate was compromised, and attackers used that access to publish poisoned releases that execute malicious code on developers' systems during compilation. The payload is an infostealer — meaning every developer workstation, CI/CD runner, and build agent that pulled the malicious version is a potential victim, and every credential, SSH key, API token, and browser session on those machines should be considered exposed.

This is the supply chain attack pattern defenders fear most: no vulnerability to patch, no exploit to block at the perimeter. The malicious code arrives through a trusted dependency, executes with the developer's own privileges inside the build process, and targets exactly the population — software engineers — whose machines hold the keys to production infrastructure. If your organization builds Rust software, you need to assume transitive exposure until proven otherwise. arrayref is a low-level utility crate; it is pulled in transitively by cryptography, serialization, and parsing libraries, so most affected teams never explicitly chose it as a dependency.

Act on three fronts immediately: determine exposure, hunt for execution, and rotate secrets.

Technical Analysis

What Happened

Attackers gained control of the maintainer account for the arrayref crate on crates.io and published one or more malicious versions. Rust crates can execute arbitrary code at build time through build.rs build scripts and procedural macros — a legitimate and heavily used language feature. The attackers abused this mechanism: when a developer or CI pipeline ran cargo build against a project resolving the poisoned version, the malicious build-time code executed locally with the invoking user's privileges and staged an infostealer.

Affected Products and Platforms

  • Affected component: arrayref crate published on crates.io (poisoned versions — verify the exact affected version range against the crates.io advisory and RustSec database before declaring yourself clean)
  • Exposure surface: Any Rust project with a direct or transitive dependency on arrayref where the lockfile resolved to a poisoned version during the exposure window
  • Platforms: Developer workstations (Windows, macOS, Linux) and CI/CD build agents (GitHub Actions runners, GitLab runners, Jenkins agents, self-hosted builders) — anywhere cargo build, cargo check, cargo test, or cargo fetch ran

Attack Chain (Defender's View)

  1. Developer or CI system resolves dependencies; Cargo.lock pins or updates to the poisoned arrayref version.
  2. cargo downloads the crate from crates.io and compiles it.
  3. The crate's build script (build.rs) executes on the local machine as a child process of the cargo/rustc build pipeline.
  4. The malicious build-time code downloads or drops the infostealer payload — typically via curl, wget, powershell, or an embedded second-stage binary.
  5. The infostealer harvests browser credentials, session cookies, SSH keys (~/.ssh/), cloud credentials (~/.aws/, ~/.azure/, ~/.config/gcloud/), .env files, and cryptocurrency wallets, then exfiltrates to attacker infrastructure.

Why This Technique Is So Dangerous

  • Execution happens before any artifact exists to scan. The malicious code runs during compilation, not in the shipped binary. Traditional endpoint scanning of build outputs misses it entirely.
  • No CVE applies. This is not a vulnerability — it is an abuse of legitimate Rust functionality. There is no patch; the fix is removing the poisoned versions and treating affected machines as compromised.
  • CI runners are high-value blast radius. Build agents frequently hold deployment credentials, signing keys, and registry tokens. A poisoned build in CI can hand attackers your entire release pipeline.
  • Transitive dependency invisibility. Most affected projects will not find arrayref in their Cargo.toml — only in Cargo.lock or cargo tree output.

Exploitation Status

This is confirmed, active, in-the-wild compromise — not theoretical. The malicious versions were published to the live crates.io registry and fetched by real builds. Any build that resolved a poisoned version executed attacker code. Treat this as an incident, not a hardening exercise.

Detection & Response

The highest-fidelity detection point is the process tree: cargo.exe, rustc.exe, or the crate build-script process (build-script-build on Windows, build_script_build on Linux/macOS) spawning shells, download tools, or scripting interpreters. Legitimate build scripts compile C code or run pkg-config — they very rarely launch PowerShell, curl out to the internet, or write executables to temp directories. That asymmetry is your detection surface.

YAML
---
title: Rust Build Script Spawning Shell or Download Utility
description: Detects cargo or Rust crate build scripts spawning shells, scripting interpreters, or download utilities — consistent with the poisoned arrayref crate executing payloads during compilation.
references:
  - https://www.bleepingcomputer.com/news/security/hackers-poison-arrayref-rust-crate-to-push-infostealer-malware/
  - https://attack.mitre.org/techniques/T1195/002/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.execution
  - attack.supply_chain_compromise
  - attack.t1195.002
logsource:
  category: process_creation
  product: windows
detection:
  selection_parent:
    ParentImage|endswith:
      - '\cargo.exe'
      - '\rustc.exe'
      - '\build-script-build.exe'
  selection_child:
    Image|endswith:
      - '\powershell.exe'
      - '\pwsh.exe'
      - '\cmd.exe'
      - '\curl.exe'
      - '\wget.exe'
      - '\certutil.exe'
      - '\mshta.exe'
      - '\wscript.exe'
      - '\cscript.exe'
  condition: selection_parent and selection_child
falsepositives:
  - Rare build scripts that legitimately shell out (e.g., some -sys crates invoking package managers); tune against a baseline of known-good build pipelines
level: high
---
title: Cargo or Rustc Initiating Network Connection to Non-Registry Host
description: Detects cargo or rustc build processes making outbound network connections to hosts other than crates.io/static.crates.io — indicative of a build script staging a second-stage payload.
references:
  - https://www.bleepingcomputer.com/news/security/hackers-poison-arrayref-rust-crate-to-push-infostealer-malware/
  - https://attack.mitre.org/techniques/T1195/002/
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.command_and_control
  - attack.t1071.001
  - attack.t1195.002
logsource:
  category: network_connection
  product: windows
detection:
  selection_image:
    Image|endswith:
      - '\cargo.exe'
      - '\rustc.exe'
      - '\build-script-build.exe'
  filter_registry:
    DestinationHostname|endswith:
      - 'crates.io'
      - 'static.crates.io'
      - 'index.crates.io'
  condition: selection_image and not filter_registry
falsepositives:
  - Private/internal crate registries and git-based dependencies (add internal registry hosts to the filter)
level: medium
KQL — Microsoft Sentinel / Defender
// Hunt: Rust build pipeline spawning suspicious child processes across Windows/Linux build agents
// Covers developer workstations and CI runners reporting into Defender / Sentinel
let suspiciousChildren = dynamic(["powershell.exe","pwsh.exe","cmd.exe","curl.exe","wget.exe","certutil.exe","mshta.exe","bash","sh","python","python3"]);
DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where InitiatingProcessFileName in~ ("cargo.exe","rustc.exe","build-script-build.exe","cargo","rustc","build_script_build")
| where FileName in~ (suspiciousChildren)
| project TimeGenerated, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, FolderPath, SHA256
| extend SuspiciousCmd = ProcessCommandLine has_any ("http://","https://","Invoke-","IEX","base64","curl ","wget ","/tmp/","AppData")
| order by TimeGenerated desc;

// Correlation: cargo builds followed within 10 minutes by access to credential stores on the same device
DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where InitiatingProcessFileName in~ ("cargo.exe","cargo")
| summarize BuildStart=min(TimeGenerated) by DeviceName
| join kind=inner (
    DeviceFileEvents
    | where TimeGenerated > ago(30d)
    | where FolderPath has_any (".ssh",".aws",".azure","gcloud",".env","Login Data","Cookies","wallets")
) on DeviceName
| where TimeGenerated between (BuildStart .. BuildStart + 10m)
| project DeviceName, BuildStart, FileAccessTime=TimeGenerated, FolderPath, FileName, ActionType;
VQL — Velociraptor
-- Artifact: SecurityArsenal.RustSupplyChainHunt
-- Hunt for Rust build processes spawning shells/downloaders and for credential-store access by build processes

SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE Name =~ '(?i)cargo|rustc|build[-_]script[-_]build'
   OR CommandLine =~ '(?i)curl |wget |powershell|invoke-webrequest|/tmp/|\.ssh|\.aws|\.env'

-- Second pass: find children of build processes (join pslist against itself)
SELECT child.Pid AS ChildPid,
       child.Name AS ChildName,
       child.CommandLine AS ChildCommandLine,
       parent.Name AS ParentName,
       parent.Pid AS ParentPid,
       child.Username AS Username,
       child.CreateTime AS CreateTime
FROM pslist() AS child
JOIN pslist() AS parent ON child.Ppid = parent.Pid
WHERE parent.Name =~ '(?i)cargo|rustc|build[-_]script[-_]build'
  AND child.Name =~ '(?i)powershell|pwsh|cmd|curl|wget|bash|sh\.exe|python|certutil|mshta'
Bash / Shell
#!/usr/bin/env bash
# arrayref supply chain exposure check — run on every Rust dev workstation and CI agent
set -euo pipefail

EXPOSED=0

echo "[*] Checking Rust toolchain and cargo-audit availability"
if ! command -v cargo >/dev/null 2>&1; then
  echo "[!] cargo not found on this host — verify manually if Rust projects exist here"
  exit 1
fi

if ! cargo audit --version >/dev/null 2>&1; then
  echo "[*] Installing cargo-audit (RustSec advisory DB check)"
  cargo install cargo-audit --locked
fi

# 1. Find every Cargo.lock on the system that references arrayref
echo "[*] Scanning for Cargo.lock files referencing arrayref"
while IFS= read -r lockfile; do
  projdir=$(dirname "$lockfile")
  echo "    -> $lockfile"
  grep -A2 '^name = "arrayref"' "$lockfile" || true
  EXPOSED=1
  # 2. Run cargo audit in each affected project for the RustSec advisory
  echo "[*] Running cargo audit in $projdir"
  (cd "$projdir" && cargo audit) || true
done < <(find / -name Cargo.lock -type f -not -path '*/target/*' 2>/dev/null | xargs grep -l '^name = "arrayref"' 2>/dev/null || true)

# 3. Check the cargo registry cache for poisoned arrayref versions already downloaded
REGISTRY="${CARGO_HOME:-$HOME/.cargo}/registry/src"
if [ -d "$REGISTRY" ]; then
  echo "[*] Checking local cargo registry cache for arrayref"
  find "$REGISTRY" -maxdepth 2 -type d -name 'arrayref-*' 2>/dev/null || echo "    none cached"
fi

# 4. Look for build-script execution artifacts in temp dirs from the exposure window
echo "[*] Checking temp directories for suspicious build-script droppers"
find /tmp /var/tmp "$HOME/AppData/Local/Temp" 2>/dev/null -maxdepth 2 -type f \( -name '*.ps1' -o -name '*build*script*' -o -name '*.sh' \) -mtime -30 2>/dev/null | head -50 || true

# 5. Pull latest yanked/advisory status from crates.io API
echo "[*] Querying crates.io for arrayref version status (yanked versions shown)"
curl -s "https://crates.io/api/v1/crates/arrayref" | grep -o '"num":"[^"]*"' | head -20 || echo "[!] API query failed — check https://crates.io/crates/arrayref/versions manually"

if [ "$EXPOSED" -eq 1 ]; then
  echo ""
  echo "[!!!] arrayref FOUND on this host. Actions required:"
  echo "  1. Cross-check the locked version(s) above against the crates.io advisory / RustSec entry."
  echo "  2. If the version is flagged: treat this host as COMPROMISED."
  echo "  3. Rotate ALL credentials stored here: SSH keys, AWS/Azure/GCP creds, .env secrets, browser sessions, CI tokens."
  echo "  4. Pin to a known-good version, purge the cargo cache: cargo clean && rm -rf \"${CARGO_HOME:-$HOME/.cargo}/registry\""
  echo "  5. Rebuild from a clean cache and re-run cargo audit."
else
  echo "[+] No arrayref references found in Cargo.lock files on this host."
fi

Remediation

There is no patch for a poisoned package — the response is removal, credential rotation, and pipeline hardening. Execute in this order:

1. Determine Exposure (Today)

  • Inventory every Rust project: grep -rl 'name = "arrayref"' --include=Cargo.lock across repos, developer machines, and build agents. Remember arrayref is usually transitive — check Cargo.lock, not Cargo.toml, and run cargo tree -i arrayref to see what pulls it in.
  • Cross-reference locked versions against the crates.io version page (https://crates.io/crates/arrayref/versions), yanked status, and the RustSec advisory database (cargo audit). Only trust versions the RustSec/crates.io advisories confirm as clean.

2. Contain and Eradicate

  • Pin to a known-good version in every affected Cargo.lock and forbid the malicious versions via cargo deny bans or a private registry allowlist.
  • Purge caches on every exposed machine: cargo clean plus deletion of $CARGO_HOME/registry (or %USERPROFILE%\.cargo\registry on Windows) to remove any cached poisoned crate. Rebuild from a clean, verified cache.
  • Treat every machine that compiled a poisoned version as compromised. The infostealer executed with the developer's privileges. Reimage high-value hosts (release engineers, anyone with production access) rather than attempting piecemeal cleanup.

3. Rotate Credentials — Assume Theft

An infostealer ran on build machines. Rotate, in priority order:

  1. CI/CD secrets and deployment tokens (GitHub Actions secrets, GitLab CI variables, Jenkins credentials, artifact registry tokens)
  2. Cloud credentials present on affected machines (~/.aws/credentials, Azure CLI tokens, gcloud ADC)
  3. SSH private keys (~/.ssh/) — revoke and reissue, especially keys authorized on production systems
  4. Code signing keys — if a build agent that signs releases was exposed, assess whether signing material was exfiltrated and revoke if in doubt
  5. Browser-stored credentials and session tokens; invalidate active sessions for developer tooling (GitHub, crates.io, package registries)
  6. Any secrets in .env files or local config on affected workstations

4. Review Maintainer-Account and Registry Hygiene

  • If you publish crates: enforce phishing-resistant MFA (hardware keys) on all maintainer accounts, enable crates.io's trusted publishing (OIDC from CI) instead of long-lived API tokens, and scope publish tokens minimally. This incident began with a maintainer account takeover — that is the upstream control failure.

5. Harden the Build Pipeline (Structural Fixes)

  • Vendor dependencies (cargo vendor) and build from a reviewed, immutable copy rather than live crates.io pulls.
  • Gate updates: use Dependabot/Renovate with a human review window; never auto-merge dependency bumps without lockfile diff review.
  • Isolate builds: run CI builds in ephemeral, network-restricted runners with no stored secrets; grant deployment credentials only to a separate, gated deploy stage that never compiles untrusted dependency code.
  • Adopt capability-locked builds where possible: evaluate sandboxed build-script execution (e.g., restricting build script network access at the egress firewall — build agents should reach crates.io and nothing else arbitrary).
  • Continuous audit: wire cargo audit and cargo deny into every pipeline; alert on new advisories for any crate in your dependency graph.
  • Deploy the detection content above — build-script process ancestry is your durable signal for the next poisoned crate, not just this one.

6. Threat-Hunt Retroactively

Search EDR and CI logs for the past 30+ days for cargo/rustc/build-script-build child processes and for credential-store access following builds (KQL above). If you find execution, scope the incident: what credentials were on that host, where do they grant access, and has anyone used them since.

Related Resources

Security Arsenal Incident Response Services AlertMonitor Platform Book a SOC Assessment incident-response Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.