⚠️ Avertissement : Cet article a été rédigé avec l’assistance d’une IA Les informations techniques sont issues de sources publiques vérifiées (mailing list Arch, BleepingComputer, lenucksi/aur-malware-check). Il est conseillé de croiser avec les sources originales avant toute action sur votre système.

Attaque AUR juin 2026 — 1 579 paquets compromis

Date de l’incident : 9–12 juin 2026
Paquets touchés : 1 579 (liste communautaire, non exhaustive)
Dépôts officiels Arch ([core], [extra], [multilib]) : non affectés


Résumé

Entre le 9 et le 12 juin 2026, l’Arch User Repository (AUR) a été la cible d’une attaque en chaîne d’approvisionnement de grande ampleur. Des acteurs malveillants ont pris le contrôle de centaines de paquets orphelins en usurpant l’identité de mainteneurs légitimes via de la forgerie de commits Git, puis ont injecté du code malveillant dans les PKGBUILD et fichiers .install.

Deux vagues d’attaque

Vague 1 — atomic-lockfile (npm)
L’attaquant a ajouté un appel npm install atomic-lockfile dans les scripts post-installation. Le paquet npm atomic-lockfile@1.4.2 contenait un hook preinstall exécutant un binaire ELF compilé en Rust — un infostealer.

Vague 2 — js-digest (bun)
Une deuxième vague, via les comptes custodiatovar et veramagalhaes, a utilisé bun install js-digest pour livrer une charge utile différente mais similaire.

Capacités du malware

  • Vol de credentials : tokens Discord, GitHub PAT, clés SSH, tokens npm/Slack/Teams, cookies navigateur, secrets Vault, credentials Docker
  • Exfiltration : upload vers temp.sh, communication C2 via service Tor onion
  • Persistance : services systemd (Restart=always) en mode utilisateur ou root
  • Rootkit eBPF : si lancé avec CAP_BPF, masque les processus, fichiers et inodes réseau — invisible pour ps, htop, ls

Réponse de l’équipe Arch

L’équipe Arch a réagi rapidement : révocation des commits malveillants, bannissement des comptes attaquants, publication d’une liste de paquets affectés. Le mainteneur légitime arojas a été innocenté — son identité avait été usurpée par forgerie de commit.


Vérifier sa machine

Le script ci-dessous télécharge la liste de référence communautaire (lenucksi/aur-malware-check), la croise avec vos paquets AUR installés via pacman -Qm, et affiche un tableau coloré dans le terminal avec le statut de chaque paquet.

Utilisation

chmod +x aur_report.sh
./aur_report.sh

Codes de sortie : 0 = propre · 2 = paquet(s) infecté(s) détecté(s)

La liste est mise en cache 1 heure dans ~/.cache/aur-malware-check/.


Script

#!/usr/bin/env bash
# =============================================================================
# aur_report.sh — Liste des paquets AUR installés avec statut malware juin 2026
# Attaque atomic-lockfile / js-digest — github.com/lenucksi/aur-malware-check
# =============================================================================

LIST_URL="https://raw.githubusercontent.com/lenucksi/aur-malware-check/master/package_list.txt"
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/aur-malware-check"
LIST_CACHE="$CACHE_DIR/package_list.txt"

# --- Couleurs ----------------------------------------------------------------
RED='\033[1;31m'; GRN='\033[1;32m'; YEL='\033[1;33m'
WHT='\033[1;37m'; DIM='\033[2m';    RST='\033[0m'

# --- Téléchargement liste infectée -------------------------------------------
mkdir -p "$CACHE_DIR"
now=$(date +%s)
mtime=0
[[ -f "$LIST_CACHE" ]] && mtime=$(stat -c %Y "$LIST_CACHE" 2>/dev/null || echo 0)
age=$(( now - mtime ))

if [[ $age -gt 3600 || ! -f "$LIST_CACHE" ]]; then
    echo -e "${DIM}[*] Téléchargement de la liste de référence...${RST}"
    if curl -fsSL --max-time 15 "$LIST_URL" -o "$LIST_CACHE.tmp"; then
        mv "$LIST_CACHE.tmp" "$LIST_CACHE"
    else
        [[ -f "$LIST_CACHE" ]] || { echo -e "${RED}[✗] Téléchargement échoué, pas de cache.${RST}"; exit 1; }
        echo -e "${YEL}[!] Téléchargement échoué — cache local utilisé.${RST}"
    fi
fi

# Charger liste infectée dans un tableau associatif (lookup O(1))
declare -A infected_map
while IFS= read -r line; do
    [[ -z "$line" || "$line" == \#* ]] && continue
    infected_map["$line"]=1
done < "$LIST_CACHE"
total_ref=${#infected_map[@]}

# --- Paquets AUR installés ---------------------------------------------------
mapfile -t aur_pkgs < <(pacman -Qm 2>/dev/null | sort -k1,1)
total_aur=${#aur_pkgs[@]}

if [[ $total_aur -eq 0 ]]; then
    echo -e "${YEL}[!] Aucun paquet AUR (foreign) détecté.${RST}"
    exit 0
fi

# --- Calcul largeurs colonnes ------------------------------------------------
max_pkg=6   # "Paquet"
max_ver=7   # "Version"
for entry in "${aur_pkgs[@]}"; do
    pkg="${entry%% *}"; ver="${entry##* }"
    (( ${#pkg} > max_pkg )) && max_pkg=${#pkg}
    (( ${#ver} > max_ver )) && max_ver=${#ver}
done

# --- Fonction d'affichage ligne ----------------------------------------------
print_row() {
    local pkg="$1" ver="$2" infected="$3"
    local pad_pkg pad_ver
    pad_pkg=$(( max_pkg - ${#pkg} ))
    pad_ver=$(( max_ver - ${#ver} ))
    local spaces_pkg; spaces_pkg=$(printf '%*s' "$pad_pkg" '')
    local spaces_ver; spaces_ver=$(printf '%*s' "$pad_ver" '')

    if [[ "$infected" == "1" ]]; then
        echo -e "  ${DIM}${RST} ${RED}${pkg}${RST}${spaces_pkg}  ${DIM}${RST} ${RED}${ver}${RST}${spaces_ver}  ${DIM}${RST} ${RED}⚠  INFECTÉ      ${RST}  ${DIM}${RST}"
    else
        echo -e "  ${DIM}${RST} ${pkg}${spaces_pkg}  ${DIM}${RST} ${DIM}${ver}${RST}${spaces_ver}  ${DIM}${RST} ${GRN}✓  Propre        ${RST}  ${DIM}${RST}"
    fi
}

sep_pkg=$(printf '─%.0s' $(seq 1 $(( max_pkg + 2 ))))
sep_ver=$(printf '─%.0s' $(seq 1 $(( max_ver + 2 ))))
sep_sta=$(printf '─%.0s' $(seq 1 18))

# --- En-tête -----------------------------------------------------------------
echo
echo -e "  ${WHT}AUR Malware Check — Attaque juin 2026 (atomic-lockfile / js-digest)${RST}"
echo -e "  ${DIM}Référence : $total_ref paquets infectés | Machine : $(hostname) | $(date '+%Y-%m-%d %H:%M')${RST}"
echo
echo -e "  ${DIM}${sep_pkg}${sep_ver}${sep_sta}${RST}"
pad_pkg=$(( max_pkg - 6 )); spaces_pkg=$(printf '%*s' "$pad_pkg" '')
pad_ver=$(( max_ver - 7 )); spaces_ver=$(printf '%*s' "$pad_ver" '')
echo -e "  ${DIM}${RST} ${WHT}Paquet${RST}${spaces_pkg}  ${DIM}${RST} ${WHT}Version${RST}${spaces_ver}  ${DIM}${RST} ${WHT}Statut          ${RST}  ${DIM}${RST}"
echo -e "  ${DIM}${sep_pkg}${sep_ver}${sep_sta}${RST}"

# --- Lignes ------------------------------------------------------------------
infected_count=0
clean_count=0
infected_list=()

for entry in "${aur_pkgs[@]}"; do
    pkg="${entry%% *}"
    ver="${entry##* }"
    if [[ -n "${infected_map[$pkg]+_}" ]]; then
        print_row "$pkg" "$ver" "1"
        infected_list+=("$pkg")
        (( infected_count++ )) || true
    else
        print_row "$pkg" "$ver" "0"
        (( clean_count++ )) || true
    fi
done

echo -e "  ${DIM}${sep_pkg}${sep_ver}${sep_sta}${RST}"

# --- Résumé ------------------------------------------------------------------
echo
echo -e "  ${WHT}Résumé${RST}  ${DIM}${RST}  Total AUR : ${WHT}${total_aur}${RST}  ${DIM}${RST}  Propres : ${GRN}${clean_count}${RST}  ${DIM}${RST}  Infectés : $(
    [[ $infected_count -gt 0 ]] && echo -e "${RED}${infected_count}${RST}" || echo -e "${GRN}${infected_count}${RST}"
)"
echo

if [[ $infected_count -gt 0 ]]; then
    echo -e "  ${RED}┌──────────────────────────────────────────────────────────────┐${RST}"
    echo -e "  ${RED}│  ⚠  ALERTE — ${infected_count} paquet(s) infecté(s) détecté(s) !$(printf '%-*s' $(( 33 - ${#infected_count} )) '')${RST}"
    echo -e "  ${RED}└──────────────────────────────────────────────────────────────┘${RST}"
    echo
    echo -e "  ${YEL}Supprimer immédiatement :${RST}"
    echo -e "  ${WHT}sudo pacman -Rns ${infected_list[*]}${RST}"
    echo
    echo -e "  ${YEL}Puis changer tous vos tokens GitHub, Discord, SSH, npm, Slack...${RST}"
    echo -e "  ${DIM}  → https://github.com/lenucksi/aur-malware-check${RST}"
    echo
    exit 2
else
    echo -e "  ${GRN}✓  Aucun paquet infecté détecté parmi vos ${total_aur} paquets AUR.${RST}"
    echo
    exit 0
fi

Que faire si vous êtes infecté ?

  1. Ne pas éteindre la machine — le rootkit eBPF disparaît au reboot, mais cela détruit les artefacts forensiques.
  2. Révoquer immédiatement tous vos secrets : clés SSH, tokens GitHub/GitLab, tokens npm, sessions Discord/Slack, credentials Docker/Podman, secrets Vault/cloud.
  3. Supprimer les paquets infectés : sudo pacman -Rns <paquet>
  4. Vérifier la persistance systemd : systemctl --user list-units --type=service
  5. Chercher les artefacts eBPF : ls /sys/fs/bpf/hidden_*
  6. Envisager une réinstallation : un rootkit rend le système fondamentalement non fiable.

Références