Cretezy Cretezy Technology & Programming

Reviewing the Arch User Repository with AI

The Arch User Repository is one of the reasons I like using Arch Linux. If a piece of software exists, there is a good chance someone has already written a PKGBUILD for it.

That convenience comes with a specific trust model: a PKGBUILD is shell code written by another user, and installing a package means running it. In June 2026, that stopped being an abstract warning.

On June 12, Arch Linux published an official notice about an active malicious-packages incident, describing a high volume of malicious package adoptions and updates. The team was removing malicious commits and trying to prevent new ones while account creation, package updates, and package adoption were restricted.

It was not a one-off incident. On July 31, Phoronix reported another wave of malicious packages and that Arch had halted package adoptions. The previous campaign had affected more than 1,500 packages, and the new wave already included dozens more. Arch disabled adoptions while the team handled the influx and again asked users to stay vigilant.

Arch’s advice was direct: review every PKGBUILD and install-script change when updating AUR packages, especially while the incident was active.

Those incidents are the specific reason I started this project. The problem was not limited to an obviously fake new package nobody had heard of. A familiar or orphaned package could be adopted, receive a malicious update, and arrive through the same update workflow as a boring version bump.

Reading every update by hand does not scale very well, but reducing the answer to “an AI said it was safe” is not useful either. I wanted another review layer for exactly these changes: automatically inspect current package updates, preserve exactly what was reviewed, and make the evidence easy to inspect afterward.

Most AUR changes are still completely ordinary version bumps. Occasionally a download moves to another domain, a repository changes owners, or a new command appears in a packaging step. Those are the changes I want to notice before installing an update.

That became aur_ai_security, a small Rust service that indexes AUR package versions, uses AI to review each package update’s Git diff, and serves the results in a web interface.

A suspicious AUR package assessment with its highlighted commit diff

You can browse the current results in the live demo.

The project is still early, but the complete index-to-review flow works. This post goes over what it records, how a check works, and the parts that took more iteration than I expected.

The problem with reviewing only a PKGBUILD

Looking at the current PKGBUILD is a useful start, but it loses the most important context: what changed?

A package downloading a binary from its established upstream GitHub release is normal. The same package suddenly downloading from an unrelated domain is much more interesting. A new checksum is expected when the version changes. A new repository owner or delivery mechanism deserves attention even if the shell code still looks clean.

The AUR already stores each package base in Git, so the useful unit of review is not just a file. It is a package version, its repository commit, the full PKGBUILD, and the diff that introduced it.

How it works

aur_ai_security has three main parts: the indexer, the AI checker, and the web interface used to catalog and review the results.

Indexer

The update-index command downloads the AUR metadata index and appends newly seen package versions to SQLite:

cargo run -p aur_ai_security -- update-index

Package metadata is scoped to package name and version. The index keeps the AUR package and package-base IDs, submitter, last-modified time, snapshot path, and popularity. Versions present in the latest index are marked current, while old rows remain available for historical checks.

The package index and check results are currently stored in a SQLite database shared by the CLI and website.

Checker

The check command selects current versions that have not already been checked with the chosen provider and model. It can be limited to exact package names or to packages modified after a timestamp:

cargo run -p aur_ai_security -- check \
  --provider codex \
  --model gpt-5.6-luna \
  --since 24h \
  --filter netcatty-bin zed-preview-bin

For each selected package, the checker:

  1. clones its AUR Git repository;
  2. records the current commit;
  3. reads the complete PKGBUILD;
  4. builds a commit diff with PKGBUILD first, followed by the other changed files;
  5. sends that context to the selected AI provider;
  6. stores the verdict, explanation, source, diff, commit, provider, and model.

The project uses Rig for its AI agent loop, which lets it support multiple providers without tying the checker to one API. OpenAI, Anthropic, and OpenRouter are currently supported. The agent has a single read_file tool so it can inspect other files in the cloned repository when the diff needs more context.

It also supports the Codex CLI, making it possible to run checks using a ChatGPT subscription instead of a separate API account. Codex runs from inside the cloned AUR repository with its shell tool and web search disabled.

Web

The web application is built with Topcoat, a server-rendered Rust web framework, and Tailwind. It provides a searchable catalog of packages and checks, with the source and diff behind each verdict available for review.

It reads the same SQLite database as the indexer and checker. Run it with:

topcoat dev --package aur_ai_security_web

From there, packages can be searched and their latest assessment, check history, PKGBUILD, and update diff can be reviewed in the browser.

paru integration

I also built two experimental branches in my paru fork to bring these checks into the package installation workflow:

Both run after paru downloads the AUR repositories and before it starts any pre-build commands or package builds.

Safe is not a score

Each check returns one of three verdicts:

  • safe for ordinary packaging behavior;
  • suspicious when a concrete change deserves human review;
  • dangerous when there is strong evidence of malicious behavior.

Suspicious and dangerous results require an explanation. Safe results do not need filler text saying that normal packaging looks normal.

The prompt treats a version and checksum bump from the same upstream source as ordinary, along with using a verified upstream binary to generate completions or metadata. Changes to domains, repository owners, or download mechanisms receive more attention.

None of these verdicts prove that a package is safe. A model can miss malicious behavior, produce false positives, or trust an upstream binary that has itself been compromised. The project stores the evidence behind each result so it can be inspected; it reviews packaging and supply-chain signals, not the contents of downloaded binaries.

What is next

The immediate work is running the checker continuously, adding notifications for dangerous results, and improving the prompt where the models are consistently too noisy or too trusting.

The goal is not to fully trust AI with deciding whether a package is safe. It is to use it as an early-warning layer: when an update is clearly malicious, I want to know quickly, see the exact source behind the verdict, and be able to address it before more users are affected.

Avatar

Who am I?

Hello! My name is Cretezy and I am a software developer. I write about programming, personal projects, and more.

See more posts here.