
Forgejo 16.0.5 - Élevé - À distance - IDOR - GET /api/v1/user/keys/{id} renvoie les clés SSH et de déploiement d'autres utilisateurs
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-keys-idor
Classe : IDOR Portée : Distante
Forgejo 16.0.5 (8d24b7d) - Forgejo
GET /api/v1/user/keys/{id} se trouve dans le groupe de l'utilisateur courant (reqToken, portée utilisateur). Le gestionnaire charge toujours public_key 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. GPG sur cette version fait les choses correctement : GetGPGKeyForUserByID(ctx, ctx.Doer().ID, id). Les champs privés supplémentaires 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.
| ID | pas encore de CVE |
| Classe | IDOR |
| Portée | Distante (read:user authentifié / session) |
| 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 | Forgejo |
| Affecté | jusqu'à v16.0.5 (8d24b7d) |
| Auth | authentifié (token read:user ou session) |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
S'inscrire ou utiliser n'importe quel compte, générer un token read:user (ou utiliser un cookie de session), 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. Il n'obtient pas la clé privée. Il n'obtient pas de shell. Il inventorie qui a accès à quoi.
| Privilège | Méthode / sink | Reconnaissance / intégrité / disponibilité | Prouvé en lab ou déduit |
|---|---|---|---|
| Lire le titre, l'empreinte et le matériel de clé publique SSH d'un autre utilisateur | GET /api/v1/user/keys/{id} en tant que propriétaire étranger | Reconnaissance (confidentialité de l'inventaire des clés publiques) | Prouvé en lab. Témoin titre FORGEJO-KEYS-IDOR-WITNESS sur l'id 1 ; la liste de l'attaquant ne contient que l'id 2 |
| Inventorier les clés de déploiement de la même manière | Même gestionnaire, lignes KeyTypeDeploy dans public_key (OwnerID 0) | Reconnaissance | Déduit de la table. Le lab a planté une clé SSH utilisateur, pas une clé de déploiement |
| Lire les principals de certificats SSH | Même gestionnaire, lignes KeyTypePrincipal. ListPublicKeys exclut ce type | Reconnaissance | Déduit de la table |
| Voir les clés appartenant à des utilisateurs limités ou privés | Aucune vérification de visibilité sur cette recherche | Reconnaissance | Déduit du gestionnaire |
JSON supplémentaire (user, key_type, read_only) | appendPrivateInformation uniquement si admin ou propriétaire | Reconnaissance | Prouvé en lab comme fermé : la réponse pour un non-propriétaire ne contenait pas de champ user |
Fermé sur cette route : le matériel de clé privée, un shell, GET /users/{username}/keys (liste publique limitée au nom d'utilisateur), GPG GET /api/v1/user/gpg_keys/{id} (404 sur un id étranger), DeletePublicKey (propriétaire/admin 403). Cross-repo GET /repos/{owner}/{repo}/keys/{id} renvoie 404 lorsque RepoID ne correspond pas.
Les correctifs de sécurité de la v16.0.5 (#14370) concernaient le RCE par git-apply et le CSRF OpenID. Ils n'ont pas fermé cette recherche. Même classe que gitea-user-keys-idor, indépendamment toujours ouverte ici.
J'ai épinglé Forgejo v16.0.5 après la vague de 2026-09. Gitea 1.27.3 avait encore cette recherche. Forgejo a divergé, j'ai donc relu le gestionnaire de clés de l'utilisateur courant à côté de GPG au lieu de copier le pack Gitea. GPG renvoie 404 sur un id étranger. SSH non.
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 limitée, le GET-by-id ne l'est pas) ; traiter DISABLE_REGISTRATION=true sur l'installateur comme une fermeture (n'importe quel compte existant suffit) ; un reverse shell. Du théâtre.
python3 forgejo-keys-idor-Abraxas-Labs.py
ou :
cd lab
./run.sh
Cible uniquement http://127.0.0.1:19310. Image codeberg.org/forgejo/forgejo:16.0.5. Deux comptes. Témoin FORGEJO-KEYS-IDOR-WITNESS.
IOC planted victim-id=1 attacker-id=2
IOC attacker-list status=200 ... title=attacker-own-key
IOC get id=1 status=200 ... FORGEJO-KEYS-IDOR-WITNESS
IOC gpg-neg id=1 status=404
SUCCESS forgejo-keys-idor victim-id=1 get-http=200 list-has-id=no gpg-http=404 FORGEJO-KEYS-IDOR-WITNESS
404 sauf si key.OwnerID == ctx.Doer().ID (ou admin du site). Rejeter KeyTypeDeploy / KeyTypePrincipal sur cette route. S'aligner sur GetGPGKeyForUserByID.
GetPublicKeyGNU Affero GPL v3.0. Voir LICENSE. Lab en loopback uniquement. Aucune garantie.