Vulnerabilities
Nextcloud built-in Collabora flaw used to plant web shells
CVE-2026-110447 in Nextcloud's Built-in CODE Server app ran attacker commands from September. Fixed versions, why disabling fails, and how to check.
If your Nextcloud server edits documents through the "Collabora Online - Built-in CODE Server" app (package name richdocumentscode), check its version now. CVE-2026-110447, published by Collabora on October 14 as advisory GHSA-g3vx-3m76-fghh, lets an attacker with no account run operating system commands as the web server user. It is rated CVSS 4.0 9.2, and every version before 26.4.303 is affected. Attackers were using it from September 10, a month before the advisory appeared.
Standalone Collabora Online servers are not affected, and neither is a Nextcloud that runs only the Nextcloud Office app (richdocuments) pointed at a separate Collabora server, Docker container or hosted service. The fix shipped on September 11 with no security notice, so many administrators who update apps on a slow schedule have no reason to think they are exposed. Disabling the app does not help: it has to be updated or removed.
How it works
The built-in app runs a private copy of Collabora Online Development Edition (CODE) on the Nextcloud host itself, from an AppImage bundled with the app. Browsers reach it through apps/richdocumentscode/proxy.php, a plain PHP script the web server runs directly, outside Nextcloud's own code and login checks. When a request arrives and no CODE process is listening, proxy.php starts one.
Up to 26.4.302, the script built that start command as a string wrapped in bash -c "...", and text taken from the request, including the URL path, ended up inside those double quotes. Inside double quotes, bash still performs command substitution, so anything written as $(...) runs before the outer command does. An attacker only has to put a command in the path. The logged requests used ${IFS} (a shell variable that expands to a space) instead of literal spaces, %2e%2e (URL-encoded ..) in the path, and a base64 payload decoded and piped to sh.
The catch for the attacker is timing. The code path runs only while the CODE server is down: after a container or server restart, an app upgrade, or a crash. With CODE running, the request is simply proxied.
Disabling the app in Nextcloud does not close it, because the web server still serves the PHP file from the app folder and proxy.php does not ask Nextcloud whether the app is enabled. A disabled app is also unlikely to have CODE running, which is the state the injection needs.
The four-line fix passes the start command to bash through PHP's escapeshellarg(), so bash no longer expands anything in it. Collabora's advisory says this is a different code path from CVE-2025-66208, an earlier command injection in the same proxy.php fixed in December 2025, and that fix does not cover this one.
What attackers are doing
The first public report, GitHub issue #354 on CollaboraOnline/richdocumentscode, came from an administrator running several Nextcloud servers, all on 26.4.302. Their logs show requests from 139.28.18.122 to /apps/richdocumentscode/proxy.php?status at 19:51 on September 10 and 09:56 on September 11 (UTC+2). The decoded payloads wrote a one-line PHP web shell into the app folder, a script that runs whatever command arrives in its c URL parameter and prints the output. The payloads also ran uname -a and sent the result to a webhook.site address, a public service that collects HTTP callbacks.
The shell files had short random names: shrf4645.php, shxa35d0.php, shx5cf91.php, shxd33ce.php and shxf4645.php. A second administrator found shx13a86.php after Nextcloud's integrity check flagged a new PHP file. A third learned of the break-in from emails about failed sudo attempts by the web server account. No report shows the attacker gaining root.
On one server, the attacker used the shell to search for credential stores and cryptocurrency wallets: KeePass databases (*.kdbx), wallet.dat, keystore.json, and folders named after Bitwarden, 1Password, Bitcoin, Electrum, Monero and Ethereum. The reporter saw no archiving or upload in the requests they reviewed. On September 14, 89.38.98.50 sent a request to a server already on 26.4.303; it got an HTTP 200 response but created no shell file, and the maintainer said the leftover process it produced was harmless.
Nobody has published how many servers were hit. A Nextcloud community forum post warned on October 3 that the flaw was being exploited with no CVE yet assigned.
What to do
1. Update the app
Update richdocumentscode to 26.4.303 or later from Apps in the admin interface, or with sudo -u www-data php occ app:update richdocumentscode (use your web server account and Nextcloud path), then confirm the version with occ app:list | grep richdocumentscode.
26.4.402, released September 24, also contains the fix but rewrote the start command again. In issue #356, administrators report CODE no longer starting after the upgrade, with proxy.php waiting on coolwsd.pid and Nextcloud Office timing out. One reporter downgraded to 26.4.303 and it worked immediately; another traced it to a PHP open_basedir setting that blocked /dev/null. Test 26.4.402 before rolling it out, and stay on 26.4.303 if it breaks.
The fixed releases need Nextcloud 30 or later. Nextcloud 29 and older are end of life and cannot install them.
2. If you cannot update today
Remove the app with occ app:remove richdocumentscode, which deletes the folder that holds proxy.php. This is the only option on Nextcloud 29 or older until Nextcloud itself is upgraded. Blocking /apps/richdocumentscode/ at the web server or reverse proxy also stops the request reaching PHP, but the advisory names only updating or removal, so treat a block as a stopgap.
3. Check whether you were hit
- Search the whole Nextcloud tree for the shells:
find /var/www/nextcloud \( -name 'shx*.php' -o -name 'shr*.php' \). Start withapps/richdocumentscode/, where the reported shells sat, and note the file times. - Run
occ integrity:check-app richdocumentscode. An extra PHP file in the app folder shows up here. - Search web server access logs back to at least September 10 for
proxy.phprequests carrying the markers, in raw and encoded form:zgrep -E 'richdocumentscode/proxy\.php.*(%2e%2e|\$\(|%24%28|\$\{IFS\}|%24%7BIFS)' /var/log/apache2/access.log*(adjust the path for nginx). Then search for any request to ashxorshrfile name, which shows commands sent to the shell. - Look in
/var/log/auth.logor the journal forsudoattempts by the web server account, and check outbound logs for connections to webhook.site.
4. If you find a shell
Delete the shell files, update the app, and assume anything the web server account could read has been exposed. That includes config/config.php, so rotate the database password, the SMTP password and any object storage keys it holds. Check what wallets, password databases and SSH keys that account could reach, and review its cron jobs and writable web folders for additions.
The wider lesson
The fix shipped on September 11 with release notes that named only the bundled CODE build, and the CVE came five weeks later. Teams that wait for an advisory before updating were exposed for that whole stretch. Internet-facing self-hosted apps need updating on a fixed schedule, whether or not the release notes mention security.
Our web penetration testing covers self-hosted collaboration servers like Nextcloud, including helper scripts that sit outside the main application's login, and our attack surface management work tracks which of these servers you expose and what they run. Open the chat and Yaali, our AI agent, will pass your question to the engineer who would do the work.
Sources: Collabora advisory GHSA-g3vx-3m76-fghh, CVE record, richdocumentscode issue #354, richdocumentscode issue #356, richdocumentscode releases, fix commit, Nextcloud community forum, The Hacker News.