Reports
MEDIA[IDOR / BOLA]#2541962

IDOR en VRoid Hub (pixiv): dar "me gusta" a un comentario oculto devolvía su texto y su autor

El endpoint de VRoid Hub para dar "me gusta" a comentarios aceptaba el ID de comentarios ocultos y devolvía en la respuesta su contenido y su autor, aunque el dueño de la publicación hubiese desactivado los comentarios.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

En la sección de medios de los personajes de VRoid Hub, el autor de una publicación puede permitir comentarios y desactivarlos después. Al hacerlo, los comentarios ya escritos dejan de verse para todo el mundo salvo para el propietario de la publicación.

El fallo estaba en otra parte: el endpoint que sirve para dar "me gusta" a un comentario, POST /api/statuses/<ID>/hearts, no comprobaba si ese comentario seguía visible para quien hacía la petición. Bastaba con enviar el ID de un comentario oculto para que el servidor registrase el "me gusta" y, de paso, devolviese en la respuesta el texto del comentario y los datos de quien lo escribió. Es una referencia directa insegura a objetos (IDOR): la API confía en el identificador sin aplicar la misma regla de visibilidad que la interfaz.

Datos del reporte:

  • Programa: pixiv (VRoid Hub)
  • Debilidad: Insecure Direct Object Reference (IDOR)
  • Severidad declarada: media
  • Enviado el 7 de junio de 2024 y divulgado el 18 de enero de 2026
  • Recompensa: sí, importe no público

Pasos de reproducción

Se necesitan dos cuentas: una víctima (dueña de la publicación) y un atacante.

  1. Crear dos cuentas en https://accounts.pixiv.net/ e iniciar sesión con ambas en https://hub.vroid.com.
  2. Con la cuenta víctima, ir a submit character, subir un personaje y bajar hasta la sección de medios de ese personaje.
  3. Subir un medio en esa sección con los comentarios permitidos.
  4. Publicar un comentario cualquiera en ese medio y, después, desactivar los comentarios. El comentario queda oculto.
  5. Obtener el ID del comentario. Para la prueba se hizo desde la cuenta víctima: ver el código fuente de la página (Ctrl+U) y buscar entityIds. Según el investigador, este paso solo sirve para la demostración; un ataque real no lo necesita.
  6. Guardar ese ID para usarlo después.
  7. Con la cuenta atacante, interceptar cualquier petición POST hacia https://hub.vroid.com/, enviarla al Repeater del proxy y cambiar la ruta y el cuerpo para que apunten al endpoint de "me gusta" con el ID del comentario oculto:
POST /api/statuses/PASTE_ID_HERE/hearts HTTP/2
Host: hub.vroid.com
Cookie: ATTACKER_COOKIES
Sec-Ch-Ua: "Opera";v="109", "Not:A-Brand";v="8", "Chromium";v="123"
Accept: application/json, text/plain, */*
Content-Type: application/json
X-Api-Version: 11
Sec-Ch-Ua-Mobile: ?0
Content-Length: 2

{}
  1. Enviar la petición. La respuesta confirma el "me gusta" e incluye el contenido del comentario oculto y quién es su autor.

Impacto

Cualquier usuario con sesión iniciada podía leer comentarios que el dueño de una publicación había ocultado al desactivar los comentarios, en cualquier publicación de la sección de medios, y saber qué cuenta los había escrito. Esos comentarios solo debían verlos el propietario de la publicación. El reporte no detalla cómo se corrigió el fallo; consta como resuelto.

Qué aprender de este caso

  • Las acciones secundarias sobre un objeto (dar "me gusta", reaccionar, marcar, denunciar) suelen ser el punto débil: el listado de comentarios respeta la visibilidad, pero un endpoint como /api/statuses/<ID>/hearts puede cargar el objeto solo por su ID sin volver a comprobarla. Al auditar, prueba cada una de esas acciones con IDs de objetos ocultos, borrados o privados.
  • Fíjate en lo que devuelven las respuestas de las acciones, no solo en si se ejecutan: aquí un simple "me gusta" respondía con el comentario completo (texto y autor). Una respuesta mínima, como el nuevo contador de "me gusta", habría limitado la fuga.
  • Al desarrollar, centraliza la regla "¿puede este usuario ver este comentario?" en una sola función y aplícala en todos los endpoints que reciben un ID de comentario, también en los que escriben. Así, ocultar comentarios desde un sitio los oculta en todos.
  • Revisa el código fuente de las páginas (en este caso, entityIds): suele mostrar qué identificadores usa la API y en qué formato, lo que ayuda a construir las peticiones de prueba.