Usuario admin y contraseña admin. Esa pareja, la que la consola web de Apache Felix trae de fábrica dentro de ForgeRock Identity Management, bastó para que Sam Curry y Shubham Shah ejecutaran código en los servidores de identidad de producción de dos fabricantes de coches y, desde allí, cambiaran el correo y la contraseña de cualquier cliente, iniciaran sesión en su nombre y abrieran las puertas y arrancaran el motor de un vehículo con su dueño al lado. Los dos fabricantes, que han pedido no ser nombrados, cerraron el acceso unas dos horas después del aviso, según el informe de Curry, publicado el 7 de noviembre de 2026.
- Hecho: la consola web de Apache Felix de ForgeRock IDM seguía en producción con admin como usuario y contraseña, y una confusión de rutas entre el WAF y Jetty permitía llegar a ella desde Internet.
- Alcance: ejecución de código en los servidores de identidad de dos fabricantes de coches, control de cualquier cuenta de cliente y envío de órdenes de apertura y arranque, demostrado en Estados Unidos y en Australia.
- Estado: sin CVE ni aviso de Ping Identity. Los dos fabricantes lo corrigieron unas dos horas después del aviso de los investigadores, a principios de 2026.
- Acción: quien ejecute PingIDM, OpenIDM o WrenIDM debe comprobar si conserva la consola Felix, retirarla o cambiar sus credenciales, y probar su WAF con las rutas codificadas del informe.
Shah lo anunció en X esa misma mañana. En su mensaje resume que trabajó con Curry a principios de año en un gran fabricante de automoción y que pudieron abrir coches a distancia en Australia y en Estados Unidos.
Earlier this year, I hacked a major automotive company with @samwcyo. We were able to remotely unlock cars in the AU and US. My writeup for AU is here: https://t.co/UAjPrav4JC and our writeup for the US here: https://t.co/4FzM1ia736
— shubs (@infosec_au) November 7, 2026
La investigación se reparte en dos informes. El de Curry, firmado por los dos, describe la cadena contra los entornos de Estados Unidos de ambos fabricantes, con fecha del 17 de febrero de 2026 en las cabeceras HTTP que reproduce. El de Shah cubre el entorno australiano de uno de ellos, con capturas de julio de 2026 y una vía de entrada distinta, unas credenciales de administrador de OpenIDM olvidadas dentro de un bundle JavaScript. Ninguno de los dos fallos tiene CVE, porque se trata de errores de configuración del despliegue, y Ping Identity, dueña de ForgeRock desde 2023, no ha publicado aviso.
Una consola de Apache Felix que la guía de Ping pide retirar antes de producción
ForgeRock Identity Platform, que Ping Identity vende hoy como PingAM y PingIDM, se divide en dos piezas en estos despliegues. Access Management (AM) ejecuta el recorrido de inicio de sesión de la app del coche y emite la sesión. Identity Management (IDM, antes OpenIDM) guarda los registros de los clientes, a los que llama managed users, y los expone por una API REST bajo /openidm/managed/user. Es el reparto habitual en una plataforma de gestión de identidades y accesos orientada a clientes. IDM ejecuta sus servicios Java como bundles OSGi dentro de Apache Felix, y Felix incluye una consola web de administración en /system/console con un gestor de configuración, ConfigMgr, que edita en caliente la configuración de los servicios.
Esa consola tiene su propia autenticación. La guía de seguridad de PingIDM avisa de que «Authentication for this console is not integrated with authentication for IDM» (la autenticación de esta consola no está integrada con la de IDM) y pide retirarla o protegerla antes de pasar a producción. El fichero conf/felix.webconsole.json que trae el producto define el usuario y la contraseña por defecto, y los dos valen admin. Ping indica cómo retirar la consola borrando sus bundles y ese fichero.
rm /path/to/openidm/bundle/org.apache.felix.webconsole*.jar
rm /path/to/openidm/bundle/openidm-felix-webconsole-7.2.0-SNAPSHOT.jar
rm /path/to/project-dir/conf/felix.webconsole.jsonQuien se quede con la consola debe cambiar al menos las credenciales de ese fichero, donde la propiedad openidm.felix.webconsole.password cae en admin si nadie la define. Los dos fabricantes conservaron la consola con el valor de fábrica. Lo que les protegía era la capa de borde, un WAF que bloqueaba /system/console, /openidm/managed/user y el resto de rutas administrativas, y que vetaba la IP de quien insistía.
Tres días antes de que se publicara la investigación, el 4 de noviembre de 2026, WrenIDM, el fork de código abierto de OpenIDM que mantiene WrenSecurity, fusionó el cambio 305, que deja vacía la contraseña de la consola Felix en la configuración de serie y genera una aleatoria de 256 bits si nadie la define, de modo que no se puede iniciar sesión hasta que un administrador fije una. El autor del cambio lo justifica en que quien entra en la consola puede instalar y arrancar bundles OSGi, es decir, ejecutar código en el servidor. Es justo lo que hicieron Curry y Shah.
La misma URL leída tres veces, por el WAF, por Jetty y por Felix
Las peticiones directas a las rutas administrativas volvían bloqueadas, mientras que las rutas normales de login y de validación de correo seguían funcionando. Shah fue variando la codificación de la URL, el método y los separadores de ruta y obtuvo respuestas distintas, señal de que el borde filtraba patrones de ruta antes de que la aplicación Java terminara de interpretarlos. Las peticiones bajo el prefijo /static llegaban al backend, así que combinó ese prefijo con barras codificadas, segmentos de punto y parámetros de ruta con punto y coma.
El primer intento, con la barra codificada entre los dos puntos y openidm, devolvió un 403 del balanceador de AWS. La variante con un punto y coma como parámetro de ruta pasó el borde, llegó al filtro de autenticación de OpenIDM y devolvió un 401. Con la consola ocurrió lo mismo. La ruta hacia el listado de bundles devolvió un 401 con la cabecera WWW-Authenticate del OSGi Management Console y, con admin:admin en la autenticación básica, el inventario de bundles en vivo. El servidor corría Apache Felix 7.0.1 con 361 bundles cargados, 343 de ellos activos. El informe de Curry recoge las cuatro peticiones y lo que respondió cada capa.
GET /static%2f..%2fopenidm/info/ping 403 (balanceador de AWS)
GET /static%2f..;/openidm/info/ping 401 (filtro de autenticación de OpenIDM)
GET /static%2f..;/system%2fconsole;/bundles/.json 401 WWW-Authenticate: Basic realm="OSGi Management Console"
GET /static%2f..;/system%2fconsole;/bundles/.json 200 con Authorization: Basic admin:admin
El diagrama de Curry resume por qué funcionó. El borde comparó la URL cruda con sus patrones y la dio por estática. Jetty, el contenedor de servlets, construyó su ruta canónica decodificando las barras, descartando los parámetros con punto y coma y resolviendo el segmento /static/.., con lo que mapeó la petición a /system/console/bundles/.json y la entregó a la consola Felix. Felix tomó el primer segmento restante, bundles, como nombre de plugin. Los investigadores enlazan el código de Jetty y el código de Felix que hacen cada una de esas lecturas.
Con la API de OpenIDM el truco no servía. El adaptador CREST de ForgeRock reconstruye el recurso a partir de la URI codificada original y su analizador de rutas solo divide por barras literales, así que en la variante con punto y coma quedaban dos elementos crudos y el enrutador buscaba openidm/info/ping en lugar de info/ping. La consola Felix fue la única ruta que sobrevivió a las dos interpretaciones. Esa discrepancia entre lo que inspecciona el WAF y lo que ejecuta el servidor es la misma lección que recogemos en nuestra guía para proteger APIs, que el WAF no puede ser el único control delante de una interfaz de administración.
Del ConfigMgr de OpenIDM a una shell dentro del proceso de identidad
Dentro de ConfigMgr, Shah localizó la fábrica de configuración org.forgerock.openidm.schedule. El planificador de OpenIDM admite tareas que invocan el servicio de scripts con código Groovy incrustado, según la documentación de Ping, y esos scripts se ejecutan dentro del proceso de identidad con acceso al entorno OSGi. Los investigadores crearon una tarea deshabilitada, de un solo disparo y no persistente, con un script Groovy que decodificaba un JAR embebido, comprobaba su SHA-256, lo instalaba con el ShellService de Felix y lo arrancaba. El JAR registraba un servlet HTTP con dos funciones, responder OK como comprobación de vida y ejecutar el comando recibido en el parámetro cmd si la petición llevaba un token propio.

Un detalle operativo explica parte del trabajo. La consola devolvía una cookie INGRESSCOOKIE porque el nombre de OpenIDM estaba balanceado entre varios nodos, y el bundle instalado solo existía en el nodo que ejecutó la tarea. Los investigadores arrastraron esa cookie de afinidad en cada petición para no cambiar de proceso a mitad de la cadena. Primero guardaron la tarea deshabilitada para releer todos los campos, después la habilitaron, sondearon el inventario de bundles hasta ver el suyo en estado activo y por último borraron la tarea para que el instalador no volviera a ejecutarse.
El servlet respondió a un ls con el directorio raíz de una instalación de OpenIDM en producción, con sus carpetas conf, script, connectors, audit, secrets y db, y la respuesta lleva fecha del 17 de febrero de 2026. En el entorno del proceso aparecían las variables idm.username e idm.password, que formaban un par de credenciales válido para el usuario idmadmin de la API administrativa local. El WAF seguía bloqueando las lecturas de usuarios desde fuera, incluso con esas credenciales, pero el servlet podía lanzar curl contra localhost:8080 desde dentro del servidor. Los investigadores omitieron el esquema de la URL porque, si incluían http en el parámetro cmd, el WAF público bloqueaba la petición externa antes de que llegara a su servlet.
Desde ahí, con las cabeceras X-OpenIDM-Username y X-OpenIDM-Password del idmadmin, el directorio de cada fabricante se podía consultar por nombre, correo, teléfono o GUID del cliente, y modificar.
De cambiar un correo en OpenIDM a arrancar el motor con el dueño al lado
El resto de la cadena usó las mismas rutas que la app oficial. Dos peticiones PATCH sobre el registro del cliente, cada una con la revisión _rev vigente en la cabecera If-Match, sustituyeron el correo por una dirección controlada por los investigadores y fijaron una contraseña nueva, con los indicadores hasToCreatePass y changePassNextLogin a false para que el login no exigiera otro cambio. Con esas credenciales completaron el recorrido MobileAppSignIn de ForgeRock, que envió el código de verificación de seis dígitos al correo recién modificado. Para automatizarlo montaron un buzón propio con API, email.samcurry.io, y el código llegó a las 11:42:18 UTC del 17 de febrero de 2026. Es lo que Curry resumió en X al publicar el informe, cuando escribió que les bastaba el nombre, el correo o el teléfono de un cliente.
Had some time off of work and was finally able to release a few blog posts: the first is about an RCE on ForgeRock that allowed us (@infosec_au) to remotely send vehicle commands for two automakers using only a customer's name, email, or phone number: https://t.co/XYlWdoAZdk
— Sam Curry (@samwcyo) November 7, 2026
La sesión de AM se cambió por un código OAuth en el cliente mobileappsdkclient, con un detalle llamativo, el reto PKCE iba en modo plain, y después por los mismos tokens de acceso, refresco e identidad que recibe la app oficial. Cambiar el correo y la contraseña no cerró la sesión del dueño, que siguió conectado en su móvil mientras la sesión de los investigadores funcionaba en paralelo. El registro del token de notificaciones push también lo controlaba el cliente, así que pudieron registrar un token propio y desviar las alertas que habrían llegado al teléfono del propietario. Tras la prueba restauraron el correo original por su _id inmutable. La contraseña no, porque nunca la conocieron, y el dueño eligió una nueva.
Con el token y el GUID del consumidor, las llamadas a /autoapi/v6/account y /autoapi/v4/vehicles/guid devolvieron el garaje de la cuenta, con VIN, modelo, estado de la suscripción y comandos admitidos por cada vehículo. El envío de órdenes dependía de la generación. Los vehículos de la rama global aceptaban doors-unlock o engine-start en /autoapi/v3/remote/global/command, los de la generación GEN17 usaban una ruta heredada con códigos como DR o RES, y la generación GEN24 del segundo fabricante pasaba por una mutación GraphQL llamada DispatchVehicleAction. Curry lo advierte en el informe, «The API accepting a command did not prove that the car had acted on it» (que la API aceptara la orden no demostraba que el coche la hubiera ejecutado). Refrescaron el estado del vehículo tras cada petición y comprobaron el resultado físico con el propietario junto al coche. Shah lo abrió y lo arrancó, después apagó el motor y volvió a cerrarlo.
En Australia bastó la matrícula y unas credenciales de staging dentro del JavaScript
El informe de Shah arranca en un sitio distinto. Al descompilar la app Android del fabricante vio que casi todo apuntaba a un dominio de telemática australiano, y entre sus subdominios había un admintool con una página titulada TEST HARNESS. La herramienta, pensada para empleados, exponía una API con la que consultar cuentas de clientes por correo, pasar de un VIN al GUID del suscriptor y de ahí a sus datos personales, muchas veces sin más autenticación que claves de API escritas en el propio bundle JavaScript. En Australia la matrícula lleva al VIN a través de los registros estatales, así que la primera mitad de la cadena quedó hecha, de la matrícula al correo del dueño.

Esa herramienta permitía provisionar funciones, añadirse como usuario secundario de una cuenta o generar códigos de acceso remoto, pero no enviaba órdenes al coche. Para eso hacía falta el token que la app recibe tras el login y el segundo factor. Shah lo resume con una frase, «Once you have that auth token, it's pretty much game over» (con ese token de autenticación, la partida está decidida). La pista para conseguirlo apareció revisando los bundles JavaScript del dominio de telemática. Uno de ellos incluía las credenciales de administrador de OpenIDM del entorno de staging del fabricante, el mismo tipo de descuido que vimos hace dos días con los secretos de Claude Code publicados en GitHub.

Las credenciales funcionaban también en producción, pero el WAF del entorno australiano devolvía un 403 de CloudFront a cualquier petición bajo /openidm/, incluso conociendo la IP de origen. Shah escribe que «I'm not sure a WAF rule has ever stopped us when we're motivated enough» (no creo que una regla de WAF nos haya parado nunca cuando estamos motivados), y que tanta inversión en reglas suele tapar algo que el propio dueño sabe que está mal.

El salto de ruta /XUI/..%2fopenidm/ pasaba el WAF y OpenIDM aceptaba las credenciales, hasta el punto de devolver una cookie session-jwt de administrador, pero el enrutador no encontraba ningún recurso en una ruta que todavía contenía el salto. Durante días la cadena se quedó ahí.

Entre tanto, la app descompilada reveló endpoints de OpenIDM a los que la aplicación móvil llamaba como usuario anonymous, como openidm/endpoint/pinService, y que el WAF no cubría. A partir de ellos, con algo de fuerza bruta, apareció un endpoint getUser que aceptaba mail, guid y phone y que, con las credenciales de administrador, devolvía el hash de la contraseña en PBKDF2-SHA512, el hash del PIN, los tokens push y los datos personales del cliente.

La pieza que faltaba la encontró un modelo de lenguaje. Shah cuenta que dejaron a GPT 5.6 Sol Ultra seis horas con el código fuente de OpenIDM más cercano a la versión desplegada y que el modelo dio con el prefijo /static%2f..%2fopenidm/, que el WAF australiano no cubría y que OpenIDM enrutaba sin la confusión de servlets. Los dos investigadores habían probado /XUI%2f..%2fopenidm/, habían recibido un 403 y habían dado por hecho que la regla se aplicaba a cualquier prefijo. Es un papel parecido al que un modelo tuvo en el exploit del kernel Linux que cubrimos hace diez días.
Con el PATCH de la contraseña sobre /static%2f..%2fopenidm/managed/user ya podían fijar la clave de cualquier usuario. El segundo factor se saltó con una petición de tipo Resource Owner Password Credentials al servidor de autorización, que devolvía un id_token sin pasar por MFA, un recorrido IDTokenROPC que lo convertía en sesión y el intercambio habitual de código por tokens de la app. La orden door-unlock al endpoint de comandos remotos abrió las puertas. Shah grabó un vídeo de 57 segundos del script en marcha, que incluye en su informe, y aclara que todas las pruebas se hicieron sobre coches propios o con permiso de sus dueños. Con los dos informes juntos, los investigadores afirman haber podido enviar órdenes a cualquier vehículo del fabricante en Australia, Estados Unidos y Canadá. Shah añade que el entorno europeo estaba más endurecido y la cadena completa no se demostró en él, mientras que Curry escribe que el acceso al directorio de identidades alcanzó a varias regiones sin nombrarlas.
Qué revisar hoy si tu organización ejecuta PingIDM, OpenIDM o un fork
Dato | Valor |
|---|---|
Producto | ForgeRock Identity Management (OpenIDM, hoy PingIDM) con la consola web de Apache Felix, y ForgeRock Access Management (hoy PingAM) |
CVE | Ninguno. Los investigadores lo describen como un error de despliegue y Ping Identity no ha publicado aviso |
Causa raíz | Consola Felix en /system/console con el usuario y la contraseña por defecto, admin, detrás de un WAF que leía las rutas de forma distinta a Jetty |
Impacto demostrado | Ejecución de código en el servidor de identidad, cambio de correo y contraseña de cualquier cliente y envío de órdenes de apertura y arranque al vehículo |
Entornos afectados | Estados Unidos y Canadá de dos fabricantes (informe de Curry) y Australia de uno de ellos (informe de Shah) |
Explotación activa | No consta. Pruebas autorizadas de los investigadores sobre coches propios o con permiso de sus dueños |
Estado | Corregido por los dos fabricantes unas dos horas después del aviso, con rotación de credenciales, a principios de 2026 |
Gravedad | Los investigadores no asignan CVSS. El impacto equivale a la toma de control de cualquier cuenta de cliente y de su vehículo conectado |
A fecha de 9 de noviembre de 2026 no existe CVE, Ping Identity no ha publicado ningún aviso y no hay boletín de INCIBE-CERT ni de CCN-CERT, porque el fallo está en la configuración de cada cliente y no hay parche que distribuir. Tampoco hay un recuento público de instalaciones de IDM con la consola Felix alcanzable, porque la ruta suele estar detrás de un WAF y no responde a un escaneo directo. La lista que sigue vale para cualquier despliegue de ForgeRock o PingIDM que gestione identidades de clientes, también los de España, y para los forks OpenIDM y WrenIDM.
- Busca la consola Felix. Comprueba en el servidor si existen los bundles org.apache.felix.webconsole y el fichero conf/felix.webconsole.json y, si no la usas, bórralos como indica la guía de Ping. Si la necesitas, define openidm.felix.webconsole.password con un valor largo y único.
- Prueba tu propio WAF con las variantes de ruta del informe. Lanza desde fuera las dos rutas codificadas del bloque anterior, la del listado de bundles y la de info/ping, contra tu hostname de IDM y confirma que el servidor no responde con 401 ni con 200. Un 401 significa que la petición ha llegado a la aplicación.
- Saca IDM de Internet. Si la app móvil solo necesita unos pocos endpoints personalizados bajo /openidm/endpoint, publica esos y deja el resto, incluidos /openidm/managed y /system/console, accesibles solo desde la red interna o a través de AM, en línea con un modelo Zero Trust.
- Rota las credenciales del idmadmin y revisa dónde viven. En los dos casos estaban en el entorno del proceso o dentro de un bundle JavaScript servido al público. Busca en tus bundles las cadenas X-OpenIDM-Username y X-OpenIDM-Password.
- Revisa el servidor de autorización. Deshabilita el grant Resource Owner Password Credentials en los clientes que no lo necesiten, exige PKCE con S256 en lugar de plain y comprueba que todo recorrido que emite una sesión pasa por el segundo factor.
- Invalida sesiones y tokens cuando cambien el correo, la contraseña o el dispositivo de una cuenta, y valida en el servidor el token push registrado en lugar de aceptar el que envía el cliente.
- Busca en los logs de IDM tareas de tipo org.forgerock.openidm.schedule creadas y borradas en minutos, bundles OSGi con nombres desconocidos y accesos a /system/console con autenticación básica. En España, la notificación de un incidente de este tipo va a INCIBE-CERT en el caso de las empresas y al CCN-CERT en el del sector público.
Para el primer punto basta con listar los bundles del directorio de instalación y leer el fichero de credenciales de la consola en cada nodo de IDM.
ls /path/to/openidm/bundle/ | grep -i webconsole
cat /path/to/project-dir/conf/felix.webconsole.jsonNinguno de los fallos de los dos informes es nuevo. La consola Felix lleva años documentada con admin como usuario y contraseña, la guía de Ping pide retirarla desde hace varias versiones y la confusión de rutas entre un WAF y un contenedor Java es un clásico de las auditorías web, igual que las interfaces de administración sin contraseña del Node-RED de Siemens que ya se explotan. La diferencia en este caso es lo que había detrás, un directorio con todos los clientes de dos marcas de coches y una API de telemática que confía por completo en el token que emite ese directorio.
Los dos fabricantes reaccionaron en dos horas, un plazo que pocos de los casos que cubrimos en el blog igualan, y rotaron las credenciales. Lo que no se sabe, porque los informes no lo dicen y las marcas no han hablado en público, es si alguien recorrió ese camino antes que los investigadores. Curry y Shah ya habían demostrado accesos remotos a vehículos de Honda, Nissan, Hyundai, Ford y Porsche en enero de 2023, a los de Kia en septiembre de 2024 y a los de Subaru en enero de 2025, siempre por el lado web, y en todos los casos la raíz fue la misma, un panel o una API de administración expuestos con menos controles de los que tiene la app del cliente. Mientras tanto, la guía de seguridad de PingIDM 7.2 sigue documentando admin como usuario y contraseña de serie de la consola, y la decisión de retirarla sigue siendo de cada cliente.



No hay comentarios todavía