AurScan

1. Overview

The AurScan module is a security-oriented monitor and static analyzer for Arch User Repository (AUR) build workflows. Its primary purpose is to detect the creation or modification of PKGBUILD files within known AUR helper build/cache directories (e.g., yay, paru, trizen, pikaur) and to perform a lightweight static security inspection of the detected PKGBUILD content.

AurScan operates entirely in user space and integrates with the UI layer by exposing two callback hooks:

  • log callback – receives human-readable operational and diagnostic messages
  • PKGBUILD detected callback – invoked when a PKGBUILD is detected or when a PKGBUILD is flagged as suspicious

The module uses GIO directory monitoring (via giomm/glibmm) rather than polling, enabling near-real-time detection with minimal overhead.


2. Platform Gating and Distribution Detection

AurScan is enabled only on Arch-based systems. The detection logic parses /etc/os-release and checks both ID and ID_LIKE for known Arch-family identifiers, including:

  • arch
  • manjaro
  • endeavouros
  • arco

If the system is not detected as Arch-based, monitoring is disabled and a log message is emitted.


3. Initialization and Callback Injection

The module is initialized via:

void initialize(
  std::function<void(const std::string&)> logCallback,
  std::function<void(const std::string&)> pkgbuildDetectedCallback)

This function stores both callbacks as module-level function objects:

  • logFunc – operational logging sink
  • pkgbuildDetectedFunc – detection notification sink

Initialization emits a localized log message confirming that AurScan is ready.


4. Monitoring Architecture

4.1 Monitor Storage and Lifecycle

All active directory monitors are retained in:

static std::vector<Glib::RefPtr<Gio::FileMonitor>> aurMonitors;

This ensures monitor objects remain alive for the duration of the monitoring session and can be cleanly cancelled during shutdown.


4.2 Recursive Directory Monitoring

AurScan monitors directories recursively using addMonitorRecursively(base). For each directory:

  • A Gio::FileMonitor is created using:
    • WATCH_MOVES
    • SEND_MOVED
  • The monitor listens to signal_changed() and filters relevant events

To reduce noise and avoid monitoring build artifacts, the recursion explicitly skips common non-actionable directories:

  • .git, .svn, .hg
  • pkg, src

Recursion uses std::filesystem::directory_iterator with skip_permission_denied and wraps traversal in try/catch blocks to prevent crashes due to permission issues or transient filesystem errors.


4.3 Dynamic Root Monitoring (New Package Directories)

Many AUR helpers create package build directories dynamically. AurScan handles this by adding a dedicated “root monitor” with addDynamicRootMonitor(root), which listens for new directories under a helper cache root.

On CREATED or MOVED_IN events, if the new path is a directory, AurScan automatically calls addMonitorRecursively() on that directory to begin recursive monitoring for PKGBUILD creation/modification.


5. Monitored Targets and Startup Flow

Monitoring is started via:

void startMonitoring()

If the system is Arch-based, AurScan monitors common AUR helper directories under the user’s home directory:

  • ~/.cache/yay
  • ~/.cache/paru/clone
  • ~/.cache/trizen
  • ~/.cache/pikaur/build

For each existing target directory, AurScan:

  1. Installs a dynamic root monitor (addDynamicRootMonitor)
  2. Installs recursive monitors for existing subdirectories (addMonitorRecursively)

Successful startup emits an “AurScan started” log message.


6. PKGBUILD Detection Logic

AurScan filters filesystem events to reduce spurious notifications. Only the following event types are considered:

  • CREATED
  • MOVED_IN
  • CHANGES_DONE_HINT

A file is treated as a PKGBUILD candidate if its path ends with the suffix:

PKGBUILD

When detected, AurScan:

  • Emits a log message including the PKGBUILD path
  • Invokes pkgbuildDetectedFunc(path) to notify downstream components

7. Duplicate Event Suppression

GIO monitors may generate multiple change events for a single user action (e.g., editor save patterns). To prevent duplicate detections, AurScan implements a short-lived cache:

  • recentDetections (unordered_set) stores recently reported paths
  • Entries are automatically removed after 1 second using Glib::signal_timeout().connect_once()

If a PKGBUILD path is already present in recentDetections, the detection is ignored.


8. Stop / Shutdown

Monitoring is stopped via:

void stopMonitoring()

Shutdown behavior:

  • Calls cancel() on each monitor (guarded by try/catch)
  • Clears aurMonitors to release resources
  • Emits a localized log message confirming deactivation

9. Static PKGBUILD Analyzer

9.1 Analysis Entry Point

AurScan includes a content inspection routine:

void scanPKGBUILD(const std::string& path)

The analyzer performs a line-by-line scan and flags potentially dangerous constructs commonly associated with malicious PKGBUILD behavior (e.g., remote code execution, destructive commands, unsafe permissions).


9.2 False-positive Reduction: Dependency Line Skipping

To reduce noise, AurScan ignores lines containing typical dependency and metadata arrays which are not executable logic:

  • depends=(...), makedepends=(...), optdepends=(...)
  • checkdepends=(...), provides=(...), conflicts=(...)

This prevents flagging harmless strings that often contain URLs or package names.


9.3 Suspicious Pattern Set

The analyzer uses a focused list of substring indicators, each mapped to a localized explanation. Examples include:

  • Remote fetch + execution (RCE indicators): curl|, wget|, | sh, | bash
  • Dynamic execution: bash -c, python3 -c
  • Destructive operations: rm -rf
  • Unsafe permissions: chmod 777, install -m 777
  • Privileged misuse: sudo inside PKGBUILD logic
  • Suspicious system writes: direct references to /etc/ and /usr/bin
  • Encoded payload hints: base64 -d

When a pattern is matched:

  • The analyzer logs a warning with the line number
  • The matched line is logged verbatim for operator review

9.4 Result Reporting Contract

If any suspicious pattern is found:

  • A “threats found” log entry is emitted
  • The detection callback is invoked with a sentinel prefix: INFECTED://<path>

If no issues are detected, AurScan emits a “clean PKGBUILD” log entry.

The INFECTED:// prefix acts as a downstream signaling mechanism, allowing consumers to distinguish between “PKGBUILD detected” and “PKGBUILD flagged as suspicious” without changing the callback signature.


10. Security and Operational Considerations

  • User-space scope: monitoring targets are within the user’s cache directories; no system-wide monitoring is performed.
  • Signal burst handling: duplicate suppression reduces event storms caused by editor save semantics.
  • Pattern-based analysis: static checks are heuristic indicators, not formal proof of maliciousness; operator review is recommended for flagged results.
  • Extensibility: additional AUR helpers, directories, and pattern rules can be added without changes to the monitoring architecture.
  • Fail-safe behavior: permission errors are contained via exception handling, preventing monitoring crashes.

Overall, AurScan provides a pragmatic monitoring layer for AUR build activity, reducing the risk of unnoticed execution of unsafe PKGBUILD constructs and improving transparency of user-space package build workflows.