Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,48 @@
# Changelog

## Unreleased
## 0.5.0

### Fixed
- **Hook fail-closed**: the ALPM hook now blocks the transaction when scans fail (git timeout, network error, etc.) instead of silently allowing unscanned packages through. Git clone/pull operations have a 30-second timeout to prevent indefinite hangs.
Major rework (this fork): traur is now a **findings reporter**, not a trust
scorer. It lists the security-relevant findings in a package and lets you
decide — no score, no tiers, no automatic blocking.

### Changed
- Output is a flat, color-coded list of findings **grouped by category**
(Pkgbuild / Behavioral / Temporal / Metadata); each finding shows the line
that triggered it.
- `scan <name>` now fetches the PKGBUILD and `.install` over HTTP from AUR's
cgit instead of cloning the repo. traur keeps **no on-disk cache** of its own.
- Local/offline scans (`--pkgbuild`, the wrapper) read on-disk files and diff
against the local `.git` when present.

### Removed
- The 0–100 trust score, the tiers (TRUSTED…MALICIOUS), category weights, and
override-gates.
- The ALPM pre-transaction hook (`traur-hook` binary and `traur.hook`).
- The `allow` / whitelist feature.
- The `bench` subcommand and the obsolete metadata-dump cache (`flate2`,
`MetaDumpPackage`, `~/.cache/traur`).

### Added
- **`-bin` source verification** (`bin_source_verification`): cross-references a `-bin` package's declared upstream URL against its `source=()` download domains. Detects fork impersonation when a package claims one GitHub org as upstream but downloads binaries from a different org. Emits `B-BIN-GITHUB-ORG-MISMATCH` (+50) and `B-BIN-DOMAIN-MISMATCH` (+30) behavioral signals.
- **Orphan takeover detection** (`orphan_takeover_analysis`): New feature that deserializes the `Submitter` field from AUR RPC and compares it against the current `Maintainer`. Emits `B-SUBMITTER-CHANGED` (+15, Behavioral) when they differ, and `B-ORPHAN-TAKEOVER` (+50, Behavioral) when combined with a git author change on an established package (>90 days). Detects the acroread-style attack vector where an attacker adopts an orphaned package and injects malicious code.
- `AurPackage` now deserializes `submitter` and `last_modified` from AUR RPC v5 responses.
- Offline `makepkg` wrapper (`contrib/makepkg-traur`) plus
`traur wrapper --enable/--disable/--status`. It scans the local
PKGBUILD/`.install` before yay/paru builds (once, on the `--verifysource`
pass) and never touches the network during a build, so it cannot stall an
install. Prompt is `[Y/n/d/p]` — `d` shows the update's git diff, `p` shows
the PKGBUILD/`.install` with the flagged lines highlighted.
- `traur scan --pkgbuild <path> --source` prints the PKGBUILD/`.install` with
the flagged lines highlighted.
- Known-malicious-list check (`B-KNOWN-MALICIOUS`): online only, short timeout,
cached, fails open.
- `.install` scripts are now run through the shell and GTFOBins analyses
(`IS-`-prefixed findings), not just pattern matching.

### Fixed
- Patterns no longer match commented-out code — whole-line `#` comments are
stripped before matching (e.g. `# modprobe configs` no longer trips a
kernel-module finding).
- `P-CHECKSUM-MISMATCH` no longer fires on source arrays built with
`name+=(...)` appends (common in kernel PKGBUILDs).
- AUR comment parser now matches the content div regardless of attribute order
(`id` before `class`), so comment-based warnings are actually detected
(issue #15).
85 changes: 41 additions & 44 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,53 @@
# traur - Pre-install Trust Scoring for AUR Packages
# traur - Findings-based security scanner for AUR PKGBUILDs

Scores AUR packages before you install them. ALPM hook for pre-install scanning.
Reports the security-relevant findings in an AUR package. No trust score, no
tiers, no ALPM hook, no automatic blocking — it lists what it found and (via the
makepkg wrapper) asks before building.

## Architecture

Feature-based with coordinator pattern:

```
PackageContext (metadata + pkgbuild + git)
PackageContext (pkgbuild + .install + optional metadata/git)
-> Coordinator runs all Features
-> Each Feature returns Vec<Signal>
-> Scorer applies weights + override gates -> final score + tier
-> Each Feature returns Vec<Signal> (a "Signal" is one finding)
-> ScanResult { package, signals } (flat list, no score/tier)
```

**Features** (`src/features/`): Self-contained analysis modules, each implementing the `Feature` trait. Each detects specific security signals.
**Features** (`src/features/`): Self-contained analysis modules, each implementing the `Feature` trait. Each detects specific findings and returns `Vec<Signal>`.

**Shared** (`src/shared/`): Reusable components (AUR API client, GitHub API client, AUR comments scraper, git ops, scoring engine, pattern loader, cache, config, output).
**Shared** (`src/shared/`): Reusable components (AUR RPC client, cgit PKGBUILD fetcher, GitHub API client, AUR comments scraper, local-git read helpers, known-malicious list check, pattern loader, config, output).

**Coordinator** (`src/coordinator.rs`): Orchestrates features, collects signals, computes final score.
**Coordinator** (`src/coordinator.rs`): Orchestrates features and assembles the flat `ScanResult`.

## Scoring
## Scan modes

Trust score 0-100 (higher = more trusted) from 4 weighted categories:
```
risk = 0.15*metadata + 0.45*pkgbuild + 0.25*behavioral + 0.15*temporal
trust = 100 - risk
```
- **Offline / local** (`scan --pkgbuild <path>`, and the makepkg wrapper):
reads the local PKGBUILD + `.install`, and diffs against the local `.git` if
present. No network — cannot hang.
- **Online by name** (`scan <package>`): fetches PKGBUILD + `.install` over HTTP
from AUR cgit (no clone, no cache), plus metadata/maintainer/GitHub/comments
and the known-malicious-list check. Adds findings the offline path can't see.

Tiers: TRUSTED (81-100), OK (61-80), SKETCHY (41-60), SUSPICIOUS (21-40), MALICIOUS (0-20).

Override gates: 47 signals across download-and-execute, reverse shells, GTFOBins binary abuse, and variable-concatenated exec escalate directly to MALICIOUS.
`Signal` retains inert `points`/`is_override_gate` fields (still populated by
some features) but they no longer affect anything and are not serialized.

## Build

```bash
cargo build --release
```

Binaries: `target/release/traur` (CLI) and `target/release/traur-hook` (ALPM hook).
Single binary: `target/release/traur`.

## Install hook
## makepkg wrapper

```bash
sudo install -Dm755 target/release/traur /usr/bin/traur
sudo install -Dm755 target/release/traur-hook /usr/bin/traur-hook
sudo install -Dm644 hook/traur.hook /usr/share/libalpm/hooks/traur.hook
```
`contrib/makepkg-traur` is the wrapper script, installed to
`/usr/share/traur/makepkg`. `traur wrapper --enable` symlinks it into
`/usr/local/bin/makepkg` so it shadows `/usr/bin/makepkg` in PATH and scans
PKGBUILDs (offline) before yay/paru builds them. `--disable` removes the
symlink; bare `traur wrapper` reports status.

## Adding a new feature

Expand All @@ -54,36 +56,31 @@ sudo install -Dm644 hook/traur.hook /usr/share/libalpm/hooks/traur.hook
3. Register in `src/features/mod.rs` (`all_features()`)
4. If pattern-based, add rules to `data/patterns.toml`

## Adding new detection patterns

Edit `data/patterns.toml`. Each pattern has: `id`, `pattern` (regex), `points`, `description`, `override_gate` (bool). Patterns are grouped by feature section name.
Network-dependent features must no-op when their inputs are absent (e.g.
`ctx.metadata.is_none()`), so the offline/wrapper path stays offline.

## Release
## Adding new detection patterns

Use `/release <version>` in Claude Code to run the full release workflow (bump version, build, GitHub release, update sha256sums, push to both AUR repos).
Edit `data/patterns.toml`. Each pattern has: `id`, `pattern` (regex), `description`, and legacy `points`/`override_gate` fields (parsed but unused). Patterns are grouped by feature section name.

## Key files

| File | Purpose |
|------|---------|
| `src/coordinator.rs` | Orchestrates features and scoring |
| `src/coordinator.rs` | Orchestrates features; builds context (HTTP online / local offline); returns flat `ScanResult` |
| `src/features/mod.rs` | Feature trait + registry |
| `src/shared/scoring.rs` | Score computation, tiers, override gates. Signal has `matched_line: Option<String>` for verbose output |
| `src/shared/scoring.rs` | `Signal` (a finding), `SignalCategory`, `ScanResult` — no scoring logic |
| `src/shared/aur_rpc.rs` | AUR RPC v5 API client |
| `src/shared/aur_git.rs` | Git clone/pull/diff operations |
| `src/shared/bulk.rs` | Batch metadata fetch, maintainer prefetch, clone-with-retry |
| `src/features/orphan_takeover_analysis/` | Submitter != maintainer detection, orphan takeover composite signal |
| `src/features/shell_analysis/` | Beyond-regex static analysis (var concat, indirect exec, char-by-char, data blobs, binary download) |
| `src/features/gtfobins_analysis/` | GTFOBins-derived patterns (117 patterns for legitimate binary abuse) |
| `src/features/bin_source_verification/` | -bin package source domain vs upstream URL mismatch detection |
| `src/features/pkgbuild_diff_analysis/` | PKGBUILD diff checking: new suspicious patterns, removed checksums, domain changes, major rewrites |
| `src/features/github_stars/` | GitHub stars checking: zero/low stars, repo not found |
| `src/features/aur_comments_analysis/` | AUR comments scanning for security-related keywords |
| `src/shared/aur_fetch.rs` | Fetch PKGBUILD + `.install` over HTTP from cgit (no clone/cache) |
| `src/shared/aur_git.rs` | Read helpers for a *local* repo (PKGBUILD/.install/git log/diff) |
| `src/shared/malicious_list.rs` | Known-compromised list check (online, cached, fail-open) |
| `src/shared/bulk.rs` | Batch metadata fetch, maintainer prefetch, fetch-with-retry |
| `src/features/shell_analysis/` | Beyond-regex static analysis (also over `.install`, IS- prefix) |
| `src/features/gtfobins_analysis/` | GTFOBins-derived patterns (also over `.install`, IS- prefix) |
| `src/features/pkgbuild_diff_analysis/` | PKGBUILD diff vs prior revision (local git only) |
| `src/shared/github.rs` | GitHub API client (star count, repo existence) |
| `src/shared/aur_comments.rs` | AUR package page comment scraper |
| `src/shared/signal_registry.rs` | Central registry of all signal definitions (pattern + hardcoded) |
| `src/shared/config.rs` | User config: whitelist, ignored signals/categories |
| `data/patterns.toml` | Regex pattern database (239 patterns). Total signals: 279 (pattern + hardcoded) |
| `src/bench.rs` | Batch benchmark (parallel scan, retry, stats) |
| `hook/traur.hook` | ALPM hook definition |
| `hook/traur-hook.rs` | Hook binary (filters AUR pkgs, runs scans) |
| `data/patterns.toml` | Regex pattern database |
| `contrib/makepkg-traur` | Offline makepkg wrapper (shipped, opt-in) |
44 changes: 1 addition & 43 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 2 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
[package]
name = "traur"
version = "0.4.1"
version = "0.5.0"
edition = "2024"
description = "Trust scoring for AUR packages"
description = "Findings-based security scanner for AUR PKGBUILDs"
license = "MIT"

[[bin]]
name = "traur"
path = "src/main.rs"

[[bin]]
name = "traur-hook"
path = "hook/traur-hook.rs"

[dependencies]
clap = { version = "4", features = ["derive"] }
reqwest = { version = "0.12", features = ["blocking", "json"] }
Expand All @@ -23,5 +19,4 @@ regex = "1"
colored = "2"
strsim = "0.11"
rayon = "1.10"
flate2 = "1.0"
indicatif = "0.17"
72 changes: 0 additions & 72 deletions FIX.md

This file was deleted.

Loading