pkglint
A security-focused linter for Arch Linux PKGBUILDs.
pkglint statically analyzes PKGBUILDs and their install scriptlets — without ever sourcing them — and reports findings about source integrity, build hermeticity, code execution, and persistence patterns, condensed into a letter grade per package. It is built on a real bash AST (mvdan.cc/sh), so the quoting/line-continuation tricks that evade regex-based scanners don't work here.
$ pkglint ~/pkgbuilds/somepkg
somepkg: grade F, 3 finding(s)
PKGBUILD:16:3: critical [PB304] a network download is piped straight into bash and executed
PKGBUILD:11:1: error [PB101] remote source "http://..." has no checksum (SKIP): the download is never verified
PKGBUILD:24:3: error [PB402] sudo escalates privileges during a build; ...
Install
go install github.com/jmelahman/pkglint@latest
Usage
pkglint [flags] [path ...] # paths are package dirs or PKGBUILD files (default: .)
--format text|json # output format
--fail-on SEVERITY # exit 1 at or above: info, warn, error (default), critical, never
--ignore PB105,PB206 # disable rules
--rules # list every rule with its documentation
Suppress a reviewed, intentional finding inline:
# pkglint: ignore=PB204
go build -o "$pkgname" .
Rules
| Group | Rules | What they catch |
|---|---|---|
| Integrity | PB101–PB107 | SKIP/weak checksums, unpinned VCS sources, unencrypted transports, source/url domain mismatches, DLAGENTS overrides |
| Hermeticity | PB201–PB206 | network access outside prepare(), pip without --require-hashes, unlocked cargo, implicit Go module downloads, disabled checksum databases |
| Execution | PB301–PB307 | top-level code, eval, decode-and-execute, download-and-execute (including eval "$(curl ...)" and source <(wget ...)" variants), /dev/tcp, unresolvable command names, embedded payloads |
| Filesystem | PB401–PB403 | writes outside $srcdir/$pkgdir, privilege escalation, setuid files |
| Scriptlets | PB501–PB502 | network access and persistence (crontabs, systemd units, shell profiles, login-capable users) in .install files running as root |
| Consistency | PB601–PB602 | PKGBUILD / .SRCINFO drift, network access in pkgver() |
pkglint --rules prints the full documentation for each.
Grading: any critical → F, any error → D, 3+ warns → C, 1–2 warns → B, otherwise A.
A grade is a static hygiene score, not a malware verdict — it measures how reviewable and reproducible a PKGBUILD is. A low grade means "worth reviewing", never "malicious", and a high grade is not an endorsement. Static analysis cannot catch a malicious upstream release pinned with a perfectly valid checksum.
Report card site
site/ generates a static "AUR Report Card" — grades, per-package finding pages,
per-rule documentation pages, results.json, and embeddable SVG badges:
go run ./site -maintainer Jamison -top 500 -out public
It downloads the AUR metadata dump once a day, fetches package snapshots politely
(throttled, cached by LastModified), and scans everything in-process.
Roadmap
- A
makepkgshim so AUR helpers lint before building (yay --makepkg pkglint-makepkg, paru[bin] Makepkg) - Sandboxed builds: containerized
makepkgwith the package artifact installed on the host viapacman -U - Hermetic builds: two-phase
makepkg -o(network) /makepkg -e(--network=none), with these lint rules enforcing the conventions that make that split work
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pkglint-0.1.0.tar.gz.
File metadata
- Download URL: pkglint-0.1.0.tar.gz
- Upload date:
- Size: 38.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
faea81b35743966c4c82b3f06487ad06f48cfc649463728b2eed395523186c6c
|
|
| MD5 |
2d10b01f3a9492a8b6836fb2458002ae
|
|
| BLAKE2b-256 |
253224c009a28111b9f4d609ed96d6f9b91f9e0ec039e23dd3a7f3296516e808
|
File details
Details for the file pkglint-0.1.0-py3-none-manylinux_2_17_x86_64.whl.
File metadata
- Download URL: pkglint-0.1.0-py3-none-manylinux_2_17_x86_64.whl
- Upload date:
- Size: 1.2 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ee5918d1400285d3bd47119a34e511bb710ae17e4b666476d8de988c0aff189
|
|
| MD5 |
4051d4f1b65ea615d73f5e18f2a7f2e4
|
|
| BLAKE2b-256 |
1c85ce837c4c385e88b68644285ec76f190051fa0d64fa38802402cd085aa17c
|
File details
Details for the file pkglint-0.1.0-py3-none-manylinux_2_17_aarch64.whl.
File metadata
- Download URL: pkglint-0.1.0-py3-none-manylinux_2_17_aarch64.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ceafefcb480859dbf00cfac6e3ab1499fc180671229563a7ead2248fdf140e7
|
|
| MD5 |
9bc2867922001581fa21f00440405c72
|
|
| BLAKE2b-256 |
ff9a20de53dca1320ef849bb8d944e6bcc1dbdbe44028f727151dbebdb652315
|
File details
Details for the file pkglint-0.1.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: pkglint-0.1.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.2 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b400045bcadccb863c2634ea52ce067ca9d1276b339bc803ecb997fdeebce46d
|
|
| MD5 |
a9089de1979a127843feb2dacb970be8
|
|
| BLAKE2b-256 |
17b0dbb7b5e2c991c3be623b5d52933a899625a619754addca3898a08c866168
|
File details
Details for the file pkglint-0.1.0-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: pkglint-0.1.0-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 1.3 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e876f9f8a0e6c6a70213496e1873b5380c8602730a1545a95b04da9ff768427a
|
|
| MD5 |
4e99a95898214b2f7e56662182739f3e
|
|
| BLAKE2b-256 |
df49bffe394f0fa58123d03e525dd398274b3630c8fdba959c103685119b57f5
|