psf-gitea-check(8)
Gitea SSH certificate principal impersonation: read-only checker (v1)
CVE-2026-109553 (GHSA-vcp6-2qc6-gvq3)
If this software is helpful, consider a donation to our 501c3 nonprofit:
https://privacysafe.foundation
Gitea resolved the principals of an SSH certificate by searching the content of
ALL stored public keys instead of only the keys registered as principals. So a
certificate that lists another user's public-key line as a principal
authenticated as that user. It applies to the HTTP signature API and to the
built-in SSH server. Rated High, CVSS 7.5.
It only applies to instances that trust a user certificate authority:
* SSH_TRUSTED_USER_CA_KEYS is set (in [server] of app.ini), AND
* either SSH_AUTHORIZED_PRINCIPALS_ALLOW=anything (documented as performing no
check on principal text), so an ordinary user can register another person's
public-key line as their own principal; or a holder of a certificate signed
by that authority can list the victim's key line.
Instances that do not trust a user CA are not affected.
Affected: Gitea up to and including 28.1.0 (the advisory confirmed it on 1.27.3)
Fixed: 28.2.0 (released 18 October 2026)
The same Gitea release fixes eight other flaws that only the update fixes.
Forgejo is a separate project: this script reads Gitea's version output and does
not judge Forgejo.
This script is read-only. It finds Gitea binaries (PATH, usual locations and
running processes), reads "gitea --version", reads app.ini, and reports whether a
user CA is trusted and how principals are allowed. It NEVER prints the CA keys or
any other value from app.ini beyond the principal policy word.
Usage:
./gitea-check.sh [command] [PATH-TO-gitea ...]
check (default) Exit 0 = nothing exposed, 1 = an affected version that trusts
a user CA, or whose configuration could not be read.
version print the script version.
Environment: GITEA_INI (space separated files) replaces app.ini discovery.
Running docker and podman containers are inspected too (see "Containers" below). An image that is
not running is not: check its tag yourself.
Containers: with no argument the check also looks in running docker and podman containers
(SCAN_CONTAINERS=1, the default; 0 skips them). A read-only probe captures the daemon's version
output and its configuration (secrets are redacted inside the container before anything is
copied) into a private temporary directory, and this script then runs once per container, in
isolation, against that copy. Paths shown as .../docker_NAME/... are inside the container NAME.The Security Patches software and this documentation are dedicated to the public domain under CC0 1.0 Universal. Other pages on privacysafe.app/docs are CC BY-SA 4.0 unless the page says otherwise.