
Preuve de concept et laboratoire pour une IDOR Gitea (CWE-639) dans GET /api/v1/user/keys/{id}, permettant à un jeton read:user authentifié d'énumérer les clés SSH et de déploiement d'autres utilisateurs.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitea-user-keys-idor
Gitea 1.27.3 - Gitea
GET /api/v1/user/keys/{id} se trouve dans le groupe de l'utilisateur courant (reqToken, rejectPublicOnly). Le handler charge toujours la ligne par ID numérique sans vérification du propriétaire. La même table contient les clés utilisateur, les clés de déploiement et les principals. Le pendant GPG fait les choses correctement : GetGPGKeyForUserByID(ctx, ctx.Doer.ID, id). Les champs privés sont protégés. Le matériel de clé publique, le titre et l'empreinte ne le sont pas. Les IDs sont séquentiels.
Un token read:user parcourt 1, 2, 3 et inventorie les clés SSH et de déploiement d'autres personnes. L'inscription ouverte en fait un bug exploitable avec un nouveau compte.
| ID | pas encore de CVE |
| CWE | CWE-639 |
| CVSS | Élevé : 7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| Produit | Gitea |
| Affecté | jusqu'à v1.27.3 (146cc3e) |
| Auth | authentifié (token read:user) |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
S'inscrire (inscription ouverte par défaut), générer un token read:user, parcourir /api/v1/user/keys/{id}. Il obtient les titres, les empreintes et le matériel de clé publique de clés qu'il ne possède pas, y compris les clés de déploiement. Il n'obtient pas la clé privée. Il n'obtient pas de shell. Il inventorie qui a accès à quoi.
Le GHSA de la clé 1.27.3 concernait la liste scopée par nom d'utilisateur plus individualPermsChecker. Ce n'était pas cette recherche.
Même tag, autre reste : git HTTP redirect SSRF.
v1.27.3 a clos la vague de GHSA 2026. Je me suis quand même attardé sur ce tag et j'ai lu le handler de clé de l'utilisateur courant à côté de celui de GPG. GPG renvoie un 404 pour un id étranger. SSH non.
seed.sh plante une clé victime avec le titre GHSA-GITEA-KEY-IDOR-WITNESS et une clé attaquant. La propre liste de l'attaquant ne contient pas le témoin. GET /user/keys/1 en tant qu'attaquant, si. GPG avec un id étranger renvoie un 404. C'est tout l'argument.
Fausses pistes déjà consignées : traiter la propre liste de l'attaquant comme la fuite (ce n'est pas le cas - la liste est scopée, le GET-by-id ne l'est pas) ; un reverse shell. Du théâtre.
Les bugs client ressemblent à des bugs produit. Un helper qui masque http.client n'envoie jamais de paquet. .recv() sur un HTTPResponse n'est pas .read(). Je le mentionne une fois parce que cela a coûté du temps et a donné l'impression, pendant une minute, que 1.27.3 avait terminé le travail.
cd lab
./run.sh
Cible uniquement http://127.0.0.1:18101.
add-key user=victim status=201 title=GHSA-GITEA-KEY-IDOR-WITNESS id=1
add-key user=attacker status=201 id=2
attacker-list status=200 ids=[2] (no witness)
get id=1 status=200 snippet contains GHSA-GITEA-KEY-IDOR-WITNESS
SUCCESS Gitea #1 user/keys IDOR
404 sauf si key.OwnerID == ctx.Doer.ID (ou administrateur du site). Rejeter les types deploy/principal. S'aligner sur GPG.
GetPublicKeyGNU Affero GPL v3.0. Voir LICENSE. Lab en loopback uniquement. Aucune garantie.