Commands
aur-scan check — pre-install review
Resolves the full transitive AUR dependency tree, scans every untrusted package, prints a reviewable tree, and can emit a CycloneDX SBOM — all before anything builds. A hijacked package is often a dependency, so the named package alone is not enough.
aur-scan check <package>...
aur-scan check <package> --sbom tree.cdx.json # write an SBOM
aur-scan check <package> --no-confirm --fail-on high # CI gate
aur-scan check --local ./mypkg # scan exact on-disk bytes
aur-scan check <package> --no-deps # named packages only, skip the tree
aur-scan check <package> --include-optional # follow optdepends tooIn scripts, pair --no-confirm with --fail-on to set the threshold you
mean. Without it, 2.1.1 and later fail closed on a Critical; 2.1.0 and earlier
exited 0 even on a Critical.
Gate and prompt. With --no-confirm the run fails at --fail-on (default
Critical). Interactively, a tripped gate asks before passing, and only a real
terminal can answer: piped or redirected input is a denial, never a yes.
Packages that couldn’t be fully analyzed (SCAN-001), fetched or resolved are
never offered a prompt; they fail the run.
Dependency tree. The tree is printed nested, each node marked [AUR]
(scanned) or [repo] (official, trusted). A dependency counts as [repo] only
when pacman says a sync repository satisfies it. A name that only an AUR package
provides is resolved through the AUR and every provider is scanned. For an AUR
dependency, the other packages that provide its name are scanned too, because
your helper can offer any of them instead; they’re listed in the notes. Anything
neither can satisfy is [UNRESOLVED] and fails the run, as does a tree cut
short by the depth or size cap: an unscanned package is never reported as clean.
timeout_seconds bounds each package’s fetch and scan, and a timeout fails
closed.
Exact bytes. By default check fetches its own copy of each PKGBUILD and
your helper re-clones and builds its own, so the bytes scanned aren’t provably
the bytes built. To scan exactly what will be built, fetch once, scan that
directory with --local, and build from it:
paru -G mypkg # download the PKGBUILD only
aur-scan check --local mypkg --fail-on critical # scan those exact bytes
makepkg -D mypkg -si # build the same directoryaur-scan install — race-free install
Fetch each AUR package once, scan those exact directories, gate on findings,
then build them in dependency order with makepkg. The bytes scanned are the
bytes built — no time-of-check/time-of-use gap.
aur-scan install <package>...
aur-scan install <package> --gate high # block on high+ findings (default: critical)
aur-scan install <package> --noconfirm # pass --noconfirm to makepkg, skip the build prompt
aur-scan install <package> --include-optional # follow optdepends too
aur-scan install <package> --sbom tree.cdx.json
aur-scan install <package> --workspace ~/build # where clones/builds go (default ~/.cache/aur-scan/build)
aur-scan install <package> --keep-build # keep build dirs after a successful install
aur-scan install <package> --force # build even though the gate tripped (deliberate)--force overrides a tripped gate, never an unscannable package: a package it
couldn’t read, and any unresolved or ambiguous dependency, still won’t build.
It’s the deliberate way through for a package whose finding you’ve reviewed,
such as one of the new 3.0.0 findings on a package that installed quietly under
2.x (see Upgrading from 2.x).
What install does and doesn’t cover, exactly: every scanned file is hashed
again immediately before makepkg runs, and any change aborts the build. It does
not cover what makepkg itself does after the scan: it still downloads
source= files, checks out VCS sources and runs pkgver(). Pinned checksums
protect the downloads; SKIP checksums and unpinned VCS sources do not, and
before building, install lists every package that relies on those.
It installs AUR packages only. A named package that lives in the official repos
is refused with a pointer to pacman -S, never silently skipped. Declining the
prompt, or running without a terminal and without --noconfirm, exits non-zero,
and AUR dependencies are installed --asdeps. It builds each AUR pkgbase with
makepkg -si in dependency order; it doesn’t cover paru-specific features like
split-package selection or chroot builds (use the shell integration’s gate
mode for those).
aur-scan scan — local PKGBUILD
aur-scan scan ./PKGBUILD
aur-scan scan ./my-package/ # directory: every file in the package tree
aur-scan scan ./pkg --format sarif # text | json | sarifA directory scan reads every file in the package tree (up to depth 8 and 4096
files; a real top-level .git is skipped, symlinks are never followed), because
a payload can be run from any of them. Binary and NUL-bearing files are scanned
with the NULs removed, and plain tar members are read in memory and reported as
archive.tar:member. A file is scanned as an install scriptlet if install=
could name it under any package name, if it ends in .install, or if it
defines a pre_/post_ scriptlet function, so a scriptlet is never missed
because install= was written in an unusual way (META-007 reports a name that
can’t be resolved soundly).
What can’t be reviewed is reported instead of skipped: a bound that was hit or a
file that can’t be read is SCAN-001 (Critical), an archive that can’t be
opened is SCAN-002 (Medium), a tar member whose path escapes is SCAN-003,
and a tar the readers would disagree about is SCAN-004 (both High).
--severity only trims the text output; if it hides a finding that trips
--fail-on, the output says so, and JSON and SARIF always carry every finding.
aur-scan system — audit what’s installed
Cross-references every installed AUR package against the IOC database, scans
cached PKGBUILDs, and flags any package that gained risky behavior since the
last scan. It exits non-zero when a finding reaches --fail-on (default
Critical), when an installed package matches the IOC database, or when a package
couldn’t be scanned (those are listed under Errors; packages with no cached
PKGBUILD are listed as skipped).
aur-scan system
aur-scan system --rescan # re-fetch PKGBUILDs from the AUR instead of the local cache
aur-scan system --fail-on high # change the exit threshold (default: critical)
aur-scan -c ti.toml system # also VT/URLhaus-check every installed package (opt-in)aur-scan ioc — indicators of compromise
aur-scan ioc # database stats + campaigns
aur-scan ioc --check <name> # is this a known-malicious indicator?aur-scan codes / explain
aur-scan codes # the full detection catalog
aur-scan codes --format markdown # or json (md is an alias of markdown)
aur-scan codes --category <category> # filter by category
aur-scan explain EXEC-REMOTE # detail on one code
aur-scan rules # the pattern rules, generated from the catalogcodes rejects an unknown --format or --category. explain, rules, ioc
and codes read only the built-in rule table, so they still run when your config
is broken (codes also reads rules_path, and falls back to the built-in list
with a warning).
aur-scan version
aur-scan version # scanner version, components and capabilitiesSince 2.2.0 it also validates your config and exits 2 if it’s broken, so
you can check before an upgrade instead of finding out when the pacman hook
aborts.
aur-scan diff and aur-scan completions
Two commands new in 2.2.0. Details in the 2.2 section of What’s in 3.0.
aur-scan diff ./mytool-1.0 ./mytool-1.1 # what changed between two versions
aur-scan diff ./old ./new --fail-on critical # CI gate: NEWLY ADDED findings only
aur-scan diff ./old ./new --format json # text (default) | json
aur-scan completions zsh > /usr/share/zsh/site-functions/_aur-scan # bash | elvish | fish | powershell | zshdiff keeps no state, so it’s safe in CI; check and install compare
against your scan history automatically.
Global flags
These apply to any command:
-c, --config <FILE> # use this config instead of the default search path
-s, --severity <LEVEL> # minimum severity to report: critical|high|medium|low|info
--fail-on <LEVEL> # (scan) exit non-zero at or above this severity — for CI gates
--no-color # disable ANSI color (also honored: the NO_COLOR env var)
-q, --quiet # only show findings
-v, --verboseWithout -c, aur-scan loads ~/.config/aur-scanner/config.toml (or
$XDG_CONFIG_HOME) if it exists, else /etc/aur-scanner/config.toml, else
built-in defaults. See Install → Configuration.
A config is also how you turn on threat intelligence:
optional VirusTotal / URLhaus lookups that are off unless you enable them and
supply your own key. A scan with threat intel off makes no network calls beyond
fetching from the AUR.
One thing worth knowing
aur-scan only ever reads. It doesn’t source the PKGBUILD, doesn’t run makepkg
to peek inside, doesn’t follow a URL it finds, doesn’t run anything it
downloads. So when a package tries to pull and run code from somewhere else, it
tells you (that’s EXEC-REMOTE, and it gives you the URL) and stops. It won’t
go fetch that code, because then the scanner would be the thing running the
payload. “We can’t see past this point” is the honest answer, and it’s the safe
one.