SEC2-039: The image build trusts a signing key fetched over HTTPS with no fingerprint check #981
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#981
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-10-16 in a read-only security review of
postuloat56fc9d531, checked by a second, independent pass.Severity: Informational · Category: Dependencies · Reference: CWE-494 (Download of Code Without Integrity Check); OWASP A08:2021 (Software and Data Integrity Failures)
Location:
docker/Dockerfile:262-268(curl -fsSL -o .../apt.postgresql.org.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc, thenapt-get install postgresql-client-17).forgejo/workflows/ci.yml:473-474(the same in the PostgreSQL job)Issue
#790 pinned the uv binary by digest and the uv installer by sha256 because "the script is the trust root for the binary it then fetches". The PGDG apt key is the same kind of trust root, fetched the same way, and left unpinned: whatever
www.postgresql.organswers becomes the keysigned-by=trusts for every package apt installs from that repository into the runtime stage. TLS is the only check.Impact
Only a compromise of postgresql.org's web host (or a TLS interception on the build host) could substitute the key and then the client packages; the released image is built on the project's own runner. Recorded because the rest of the build's trust roots were pinned deliberately.
Fix
Commit the ASCII-armoured key under
docker/andCOPYit, and have the CI job use the same file. This is cheaper and sturdier than a fingerprint check: the runtime stage is a slim image with nogpg, sogpg --show-keyswould mean installinggnupgfor one check, and a sha256 of the downloaded.ascwould break whenever PGDG re-exports the key with a refreshed expiry. If the fingerprint route is chosen instead, compare the full 40-hex fingerprint PGDG publishes for key idACCC4CF8on postgresql.org's Debian download page. Done when:tests/test_image_build.pyasserts the Dockerfile's key step copies a committed key (or carries the fingerprint check) and fetches nothing.Related
#790 (closed) - pinned uv and its installer; the apt key is not named in it.