joplin-server-bin
The PKGBUILD downloads and extracts layers from a Docker image hosted on Docker Hub without bundling the image in source=(), using an unverifiable checksum check; while the checksum verification mitigates risk, the lack of source transparency and reliance on runtime downloads from an untrusted host constitutes a supply-chain risk.
Triggered rules
external_download_not_in_source
curl/wget fetches a URL on a non-allowlisted host that is not part of source=(), so it is not checksum-verified by makepkg.
-
PKGBUILD:38
token="$(curl -s "https://auth.docker.io/token?service=$_service&scope=repository:$_image:pull" | jq -r .access_token)" -
PKGBUILD:40
idigest="$(curl -s -H "Authorization: Bearer $token" -H "Accept: $_accept" "https://$_registry/v2/$_image/manifests/$pkgver" \ -
PKGBUILD:48
curl -s -H "Authorization: Bearer $token" -H "Accept: $_vnd" "https://$_registry/v2/$_image/manifests/$idigest" \ -
PKGBUILD:52
count=$(curl -s --follow -H "Authorization: Bearer $token" "https://$_registry/v2/$_image/blobs/$ldigest" \
llm_review
An AI model (qwen/qwen3-235b-a22b-2507) reviewed this and agrees it is MEDIUM (confidence 95%): The PKGBUILD downloads and extracts layers from a Docker image hosted on Docker Hub without bundling the image in source=(), using an unverifiable checksum check; while the checksum verification mitigates risk, the lack of source transparency and reliance on runtime downloads from an untrusted host constitutes a supply-chain risk.
PKGBUILD
4 offending line(s) highlighted_pkgname=joplin-server
_image=joplin/server
pkgname="$_pkgname-bin"
pkgver=3.7.3
pkgrel=1
pkgdesc='Joplin Server, via Docker image'
arch=('any')
url="https://hub.docker.com/r/$_image"
license=('custom:Joplin-Server-Personal-Use-License')
depends=('nodejs' 'pnpm' 'pm2')
makedepends=('jq')
source=(
"$_pkgname.service"
"$_pkgname.sysusers"
"$_pkgname.tmpfiles"
'https://raw.githubusercontent.com/laurent22/joplin/dev/.env-sample'
)
_imagesum='sha256:ed32018183f7771818f9d856b1bb9830b22424243496eae1ce08c957a42f296c'
sha256sums=('2b4bd101041ea99d90d735b65b6bd54573e7424e57fc127c90082034c19c1cde'
'2f3cea9bed6f79d7c93721dd1acb7c3b5c0368be264ae2894bd66034634e694d'
'55455d0ebfcb6ef72b8c4fe934a69ccfd9089f881058933d7cba0c07d7aaffc0'
'e85770c7a0391baa7cf18edeeb64b6a8fe2ccb409d31294d2bde4cd8096cf80f')
backup=("etc/$_pkgname.env")
provides=("$_pkgname")
options=(!strip !debug)
_vnd='application/vnd.docker.distribution.manifest.v2+json'
_vndlist='application/vnd.docker.distribution.manifest.list.v2+json'
_accept="$_vnd,$_vndlist"
_service=registry.docker.io
_registry=registry-1.docker.io
_path=home/joplin/packages
prepare() {
echo "Authenticating to '$_service'"
token="$(curl -s "https://auth.docker.io/token?service=$_service&scope=repository:$_image:pull" | jq -r .access_token)"
echo "Looking up image '$_image:$pkgver' via '$_registry'"
idigest="$(curl -s -H "Authorization: Bearer $token" -H "Accept: $_accept" "https://$_registry/v2/$_image/manifests/$pkgver" \
| jq -r 'if .mediaType == "'"$_vndlist"'" then .manifests[0] else . end | .digest')"
if ! [ "$idigest" = "$_imagesum" ]; then
echo >&2 "Error: image checksum mismatch for '$_image:$pkgver'"
echo >&2 "(expected '$_imagesum', found '$idigest')"
exit 1
fi
echo "Listing layers for manifest '$idigest'"
curl -s -H "Authorization: Bearer $token" -H "Accept: $_vnd" "https://$_registry/v2/$_image/manifests/$idigest" \
| jq -r '.layers[].digest' \
| while read ldigest; do
echo "Fetching layer '$ldigest'"
count=$(curl -s --follow -H "Authorization: Bearer $token" "https://$_registry/v2/$_image/blobs/$ldigest" \
| 2>&1 tar xzv $_path | grep -Ev 'Not found in archive|Exiting with failure status' | wc -l)
if [ $count -gt 0 ]; then echo "* unpacked $count files"; fi
done
}
package() {
install -d -m 0755 "$pkgdir/usr/lib/$_pkgname"
cp -a "$_path/"* "$pkgdir/usr/lib/$_pkgname/"
install -D -m 0644 "$_path/server/LICENSE.md" "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
install -D -m 0640 .env-sample "$pkgdir/etc/$_pkgname.env"
ln -s '/var/lib/joplin/logs' "$pkgdir/usr/lib/$_pkgname/server/logs"
ln -s '/var/lib/joplin/temp' "$pkgdir/usr/lib/$_pkgname/server/temp"
install -D -m 0644 "$_pkgname.service" "$pkgdir/usr/lib/systemd/system/$_pkgname.service"
install -D -m 0644 "$_pkgname.sysusers" "$pkgdir/usr/lib/sysusers.d/$_pkgname.conf"
install -D -m 0644 "$_pkgname.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$_pkgname.conf"
}
Changes since previous scan
--- PKGBUILD @ 2026-10-23 00:02+++ PKGBUILD @ 2026-11-01 00:21@@ -2,7 +2,7 @@ _image=joplin/server pkgname="$_pkgname-bin"-pkgver=3.7.2+pkgver=3.7.3 pkgrel=1 pkgdesc='Joplin Server, via Docker image' arch=('any')@@ -16,6 +16,7 @@ "$_pkgname.tmpfiles" 'https://raw.githubusercontent.com/laurent22/joplin/dev/.env-sample' )+_imagesum='sha256:ed32018183f7771818f9d856b1bb9830b22424243496eae1ce08c957a42f296c' sha256sums=('2b4bd101041ea99d90d735b65b6bd54573e7424e57fc127c90082034c19c1cde' '2f3cea9bed6f79d7c93721dd1acb7c3b5c0368be264ae2894bd66034634e694d' '55455d0ebfcb6ef72b8c4fe934a69ccfd9089f881058933d7cba0c07d7aaffc0'@@ -38,6 +39,11 @@ echo "Looking up image '$_image:$pkgver' via '$_registry'" idigest="$(curl -s -H "Authorization: Bearer $token" -H "Accept: $_accept" "https://$_registry/v2/$_image/manifests/$pkgver" \ | jq -r 'if .mediaType == "'"$_vndlist"'" then .manifests[0] else . end | .digest')"+ if ! [ "$idigest" = "$_imagesum" ]; then+ echo >&2 "Error: image checksum mismatch for '$_image:$pkgver'"+ echo >&2 "(expected '$_imagesum', found '$idigest')"+ exit 1+ fi echo "Listing layers for manifest '$idigest'" curl -s -H "Authorization: Bearer $token" -H "Accept: $_vnd" "https://$_registry/v2/$_image/manifests/$idigest" \ | jq -r '.layers[].digest' \Scan history
| Scanned at (UTC) | Severity | Rules |
|---|---|---|
| 2026-11-01 00:21:48 | Medium | 2 |
| 2026-10-31 00:07:41 | Medium | 2 |
| 2026-10-30 00:29:30 | Medium | 2 |
| 2026-10-29 00:13:55 | Medium | 2 |
| 2026-10-28 00:06:54 | Medium | 2 |
| 2026-10-27 00:23:28 | Medium | 2 |
| 2026-10-26 00:12:40 | Medium | 2 |
| 2026-10-25 00:20:48 | Medium | 2 |
| 2026-10-24 00:14:55 | Medium | 2 |
| 2026-10-23 21:38:30 | Medium | 2 |
| 2026-10-23 00:02:19 | Medium | 2 |
| 2026-10-22 00:13:10 | Medium | 2 |
| 2026-10-21 00:12:50 | Medium | 2 |
| 2026-10-20 00:10:31 | Medium | 2 |
| 2026-10-19 00:03:55 | Medium | 2 |
| 2026-10-18 00:06:55 | Medium | 2 |
| 2026-10-17 00:21:55 | Medium | 2 |
| 2026-10-16 00:12:47 | Medium | 2 |
| 2026-10-15 00:28:05 | Medium | 2 |
| 2026-10-14 00:06:47 | Medium | 2 |