Last active
June 15, 2026 14:45
-
-
Save AlexZeitler/9da08236e5a112b457102c8dd8f5bdcd to your computer and use it in GitHub Desktop.
Check for infected AUR packages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # | |
| # check-aur-infected.sh | |
| # Checks the locally installed AUR / foreign packages against the published | |
| # list of compromised AUR packages. | |
| # | |
| # Options: | |
| # -v | --verbose Enable debug output (written to stderr) | |
| # (alternatively: DEBUG=1 as an environment variable) | |
| # | |
| # Exit codes: | |
| # 0 none of your packages are on the list | |
| # 1 at least one affected package is installed | |
| # 2 list could not be fetched (network / HTTP error) | |
| # 3 list looks empty/implausible -> format may have changed, no all-clear | |
| set -uo pipefail | |
| URL="${AUR_LIST_URL:-https://md.archlinux.org/s/SxbqukK6IA}" | |
| MIN_ENTRIES="${AUR_MIN_ENTRIES:-50}" # lower bound for the plausibility check | |
| DEBUG="${DEBUG:-0}" | |
| # Parse flags | |
| for arg in "$@"; do | |
| case "$arg" in | |
| -v|--verbose) DEBUG=1 ;; | |
| -h|--help) | |
| sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//' | |
| exit 0 ;; | |
| *) echo "Unknown option: $arg" >&2; exit 64 ;; | |
| esac | |
| done | |
| # Debug helper: writes to stderr only, and only when DEBUG is enabled | |
| dbg() { [[ "$DEBUG" == 1 ]] && printf '[debug] %s\n' "$*" >&2; return 0; } | |
| dbg "Start $(date '+%F %T')" | |
| dbg "URL = $URL" | |
| dbg "MIN_ENTRIES = $MIN_ENTRIES" | |
| # 1) Fetch the list --------------------------------------------------------- | |
| dbg "Fetching list ..." | |
| if ! raw=$(curl -fsSL --retry 2 "$URL"); then | |
| echo "Error: could not fetch the list from $URL." >&2 | |
| exit 2 | |
| fi | |
| dbg "Fetched = ${#raw} bytes" | |
| # 2) Extract package names (step by step so each stage is countable) -------- | |
| clean=$(printf '%s' "$raw" | sed 's/<[^>]*>//g') | |
| dbg "After sed = ${#clean} bytes (HTML tags removed)" | |
| tokens=$(printf '%s' "$clean" | tr -s '[:space:]' '\n' | grep -c .) | |
| dbg "Tokens (split) = ${tokens} (split on whitespace)" | |
| mapfile -t INFECTED < <( | |
| printf '%s' "$clean" \ | |
| | tr -s '[:space:]' '\n' \ | |
| | grep -E '^[a-z0-9][a-z0-9_.+-]*[a-z0-9]$' \ | |
| | sort -u | |
| ) | |
| dbg "Filtered+uniq = ${#INFECTED[@]} valid package names" | |
| if [[ "$DEBUG" == 1 && ${#INFECTED[@]} -gt 0 ]]; then | |
| dbg "First 5 : ${INFECTED[*]:0:5}" | |
| dbg "Last 1 : ${INFECTED[-1]}" | |
| fi | |
| # 3) Plausibility check ----------------------------------------------------- | |
| if (( ${#INFECTED[@]} < MIN_ENTRIES )); then | |
| echo "Warning: only ${#INFECTED[@]} entries parsed (expected >= ${MIN_ENTRIES})." >&2 | |
| echo "The source format has probably changed. Please verify manually." >&2 | |
| exit 3 | |
| fi | |
| # 4) Load local foreign packages ------------------------------------------- | |
| foreign=$(pacman -Qmq | sort) | |
| foreign_n=$(printf '%s' "$foreign" | grep -c .) | |
| dbg "Foreign pkgs = ${foreign_n} installed locally (pacman -Qmq)" | |
| # 5) Compute the intersection ----------------------------------------------- | |
| hits=$(comm -12 \ | |
| <(printf '%s\n' "$foreign") \ | |
| <(printf '%s\n' "${INFECTED[@]}")) | |
| dbg "Matches = $(printf '%s' "$hits" | grep -c .)" | |
| # 6) Result ----------------------------------------------------------------- | |
| if [[ -n "$hits" ]]; then | |
| n=$(printf '%s\n' "$hits" | grep -c .) | |
| echo "WARNING: ${n} affected package(s) installed on this system:" | |
| printf '%s\n' "$hits" | sed 's/^/ - /' | |
| echo | |
| echo "Checked against ${#INFECTED[@]} listed packages from ${URL}" | |
| exit 1 | |
| else | |
| echo "OK: none of your installed foreign packages are on the list." | |
| echo "(checked against ${#INFECTED[@]} listed packages)" | |
| exit 0 | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment