Malware · · 14 min read
The Nextcloud app that starts Collabora runs a shell command while the editor is down
CVE-2026-110447 is in the optional Built-in CODE Server, not in Collabora Online itself. The command runs only while that server is stopped, and disabling the app leaves the script in place.

On October 14, 2026, Collabora published GHSA-g3vx-3m76-fghh for CVE-2026-110447. A request to one PHP file in an optional Nextcloud app can run an operating-system command as the web server’s account. The next day BleepingComputer reported that the flaw had been used since September 10 to plant PHP shells on Nextcloud servers. This post is the mechanism behind that headline: which program is actually listening, why the dangerous line runs only while that program is down, and why turning the app off does not close the hole.
The flaw is not in Collabora Online as a separate server. Docker images, RPM and DEB packages, and Nextcloud All-in-One are outside it. So is a Nextcloud that has the office app and points it at a Collabora server you installed yourself.
Two apps that share a name
Nextcloud’s browser office is two apps.
Nextcloud Office is the app whose folder is richdocuments. It is the part users see. It talks to an editor using WOPI, the Web Application Open Platform Interface: Nextcloud holds the file and issues a short-lived token, and the editor fetches the bytes with that token. Nextcloud is the host. The editor is a different process.
Collabora Online - Built-in CODE Server is the app whose folder is richdocumentscode. CODE means Collabora Online Development Edition. The app’s own README describes it as a built-in server for personal use or a small team, slower than a standalone Collabora, and without the scaling features of one. It downloads an AppImage, a single file that contains the editor and its libraries, and runs that file on the same machine as Nextcloud. The process inside is coolwsd. An ARM64 build is a separate app, richdocumentscode_arm64. The x86_64 app refuses anything else: its setup check returns not_x86_64 when php_uname says the machine is not x86_64, not_linux off Linux, appimage_missing when the file is not there, and no_fontconfig when the dynamic linker’s cache has no fontconfig. It also refuses a musl system. The check runs the AppImage with LD_TRACE_LOADED_OBJECTS set, which prints the libraries a glibc loader would pull in, and treats a failure as no_glibc.
That is the whole of the affected install. A site that only has richdocuments, and a site whose editor is a container or a distro package, does not have this PHP file.
proxy.php is a proxy, and it is also the thing that starts the editor
The file is apps/richdocumentscode/proxy.php. The web server runs it the way it runs any other PHP file in a directory it is allowed to execute. The Hacker News, reading the script, notes that it does not load Nextcloud. Nothing in the request has to be a logged-in Nextcloud user. The advisory’s score matches that: no privileges required, no user interaction.
The published script accepts two query shapes. status asks whether the editor is up. req= followed by a path is a document request, and the path has to begin with /. For a document request the script opens a TCP socket to localhost port 9983, with a three-second timeout, and writes the request through that socket. The response comes back the same way. Port 9983 is also the port on the coolwsd command line an administrator pasted into the public bug report. The “proxy” is this hand-written pipe. There is no general reverse proxy in the file.
If that socket does not connect, and the setup check passes, and coolwsd is not already running, the script starts it. A status request takes the same branch. The requests a hoster pasted on September 11 were status requests. Once the socket is open, a later request does not build a start command. It only forwards.
The start itself is serialized with a lock file opened in exclusive-create mode. A lock whose ctime is older than five minutes is deleted first, so a crashed start does not block the next one forever. The pid file is removed before the new process is spawned, then the script waits until the local socket answers and deletes the lock. That lock is there so two requests do not start two editors. It is not an authentication check.
Where the request became a shell command
The class of bug is CWE-78, an operating-system command that includes text the requester supplied.
PHP’s exec of a single string hands that string to a shell. The Hacker News, comparing the releases, writes that through 26.4.302 the start command was built that way, and that text from the request, including the path, sat inside double quotes. Double quotes in bash suppress word splitting and globbing. They do not suppress command substitution. A substitution in the request ran as the web server’s account, and only on this start branch. The advisory states the same limit in one sentence: the command can be run only while the built-in CODE server is not already running.
The copy of proxy.php on the current public branch no longer builds that string for exec. It builds an argument list and passes it to proc_open: bash, -c, a script, the AppImage path, then the options. An argument list is not parsed as shell syntax. The Hacker News describes the change as four lines, committed under the message “tidy up how the coolwsd launch command is built,” written by Caolán McNamara on August 20, 2026. It was not in 26.4.302, which came out on August 31. It was committed on September 9. Version 26.4.303, with the change, came out on September 11. The release notes named the bundled CODE build. They did not say the build was a security fix. A person reading the bug report on September 30 said the same thing: the notes did not mention one.
The setup check on the current file still calls exec, twice, for the glibc probe and the fontconfig probe. Those strings are written in the script. They are not the request. The bug was the request being part of the start command.
The editor being down is a normal moment
A server that has been up for weeks will not take the start branch. The window opens when nothing is listening on that local port, or when the script decides the process that is listening is the wrong build.
The wrong-build check is a hash. When the app is packaged, a hash of the bundled coolwsd is written into the PHP. On a status request, if the socket connects, the script fetches http://localhost:9983/hosting/capabilities and reads productVersionHash. If the two hashes differ, it sends the running process SIGTERM, waits up to ten seconds, and starts a new one if the port is still closed. An upgrade replaces the PHP and the AppImage together, so the new PHP sees the old process, the hashes differ, and the start branch runs. A crash, a reboot, or a host that stopped the process does the same thing without a hash mismatch. The advisory’s attack requirements field, AT:P, is this prerequisite: the built-in server has to be stopped, or about to be replaced.
The first requests a hoster logged were on September 10, the day after the fix was committed and the day before 26.4.303 was published. Those servers were on 26.4.302. The French health-sector notice says exploitation was confirmed on that version, and that the flaw is being exploited.
What was on the servers afterward
The report is CollaboraOnline/richdocumentscode issue 354, opened September 11 by a hoster running several Nextcloud servers. The requests created PHP files in the app directory. The names followed a pattern Michael Meeks later told people to delete: shx and then more characters, with a .php suffix. Those files were web shells. From there, BleepingComputer reported, the intruders searched the server for password databases, password-manager files, and cryptocurrency wallets.
One administrator, writing on September 14 after moving to 26.4.303, pasted a process list that still contained the malicious request. It was sitting in a coolwsd option, remote_font_config.url. Meeks’s reply was that the list looks alarming and should be harmless once the extra PHP files are gone: the option points the editor at a font configuration that is not a real server. The same list showed coolwsd started with security.capabilities and security.seccomp set to false, and the child processes started with --nocaps and --noseccomp. That is a property of the launch that host saw. It is also a reason not to treat “Collabora sandboxes documents” as a description of this app. The command the bug runs is the web server’s PHP process, which is outside coolwsd anyway.
The same report asks whether a request was still reaching proxy.php of an app that had been deactivated. The advisory answers the practical version of that question. Disabling the app in Nextcloud’s settings does not remove the file, and the web server does not ask Nextcloud whether the app is enabled before it executes a PHP file. The fix is to upgrade the app to 26.4.303 or newer, or to remove the app. Nextcloud 29 and older are end of life, and the advisory says those installs should upgrade Nextcloud or remove the app.
A different administrator found out on September 18 because the server emailed about failed sudo attempts. The mail does not say which account ran sudo. What the web server account can do without sudo is already enough to matter: it can read Nextcloud’s config/config.php, which is where the database password and the instance secret live, and it can read the data directory the server is storing for users. A shell that never reached root still had those files.
On September 29 a comment on the same issue said ransomware operators had started using the bug in the previous week. BleepingComputer asked and could not confirm a ransomware deployment. Both sentences belong in the record. Neither one is a count of victim servers. Nobody who has published on this has given one.
9.2 and 9.8 are two scales, not two measurements
Collabora’s advisory scores it CVSS 4.0 at 9.2:
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Network, low complexity, no privileges, no click, high impact on the confidentiality, integrity, and availability of the vulnerable system, no impact scored on a subsequent system. The AT:P is the stopped-server requirement. CVSS 4.0 added that field so a precondition can lower the score without pretending the attack is complicated.
The French health-sector notice at cyberveille.esante.gouv.fr scores the same CVE at 9.8 on CVSS 3.1, and says exploitation was confirmed against 26.4.302. CVSS 3.1 has no attack-requirements field. A network attack with no privileges and high impact on all three lands at 9.8 whether or not the editor has to be down. The two numbers are both published. They are not a disagreement about how bad a shell is. They are a disagreement about whether the score should mention the precondition.
This is also not last year’s bug in the same file. CVE-2025-66208 is a command injection in proxy.php that depends on a reverse proxy trusting X-Forwarded-Host. Collabora fixed that one in 25.04.702, on December 3, 2025, and said a typical default setup was not affected. The current advisory says that fix does not stop CVE-2026-110447. Patching the 2025 bug and staying on 26.4.302 leaves this one in place.
The fix shipped on September 11. The CVE is dated October 14.
The public timeline, from the repository, the bug report, Collabora’s October 15 post, and the two news articles:
- August 20. The tidy-up of the launch command is written, according to The Hacker News. It is not labeled as a security fix.
- August 31. 26.4.302 is released, without that change. This is the version the September attacks hit.
- September 9. The change is committed.
- September 10. The hoster’s logs show the first successful requests. The servers are on 26.4.302.
- September 11. 26.4.303 is released, and the hoster opens issue 354. In the thread, Meeks writes that it affects the Development Edition, and only the mode that downloads a local AppImage. He points at a GitHub post about the advisory database being behind.
- September 14. Meeks confirms 26.4.303 is the fixed release and tells people to remove leftover
shx*.phpfiles. The same day, an administrator asks whether requests were still reachingproxy.phpafter the app had been deactivated. - September 18. Failed
sudomail is how another server’s owner noticed. - September 29. A comment asks for a CVE and says ransomware operators had begun using it. That second claim is the one BleepingComputer could not confirm.
- September 30. A reader points out that the 26.4.303 notes do not mention a security fix.
- October 2. Someone posts the comparison of 26.4.302 and 26.4.303.
- October 3. A Nextcloud forum thread warns built-in CODE users that the bug is already being used and that no CVE exists yet.
- October 14. The advisory and CVE-2026-110447 are published. Caolán McNamara closes the issue with a link to the advisory.
- October 15. Collabora’s blog post, and BleepingComputer’s article.
Collabora’s account of the gap is the CVE paperwork. They say GitHub’s assignment, which used to take about a day, was taking many weeks, and that this year’s incoming reports were on the order of ten years of their previous volume, which they attribute to reports produced with AI. They say they are applying to be a CVE Numbering Authority so they can assign numbers themselves. They also say the built-in app is not the install they recommend, that it is a minority of Nextcloud users, and that no Collabora Online customer was affected. They thank Nextcloud and say the person who reported the bug will be credited. The Hacker News, reading the advisory, says that credit is the GitHub user wwwshellcodeit. Neither the advisory nor the bug thread says when the report arrived.
Nextcloud’s account, given to BleepingComputer, is different. They said Collabora reported the bug in mid-September, the update was already in the app store, the disclosure waited so people had time to update, and Nextcloud had not seen widespread exploitation.
Those two accounts can both be things the organizations believe. The public issue is still the part a reader can check. From September 11 a hoster was describing compromised servers on the version before the fix. From September 14 a Collabora maintainer was saying 26.4.303 was the fix. The CVE identifier did not exist until October 14.
BleepingComputer quotes Second Security on a wider pattern: the median time from a public fix to a CVE was 39 days in August 2026, up from 5.1 days in January, and public exploit code often showed up within hours of a fix and days before the CVE. That is Second Security’s measurement, as reported by BleepingComputer. It is the context Collabora’s month sits in, not a number from Collabora’s own logs.
Landlock arrived in the same upgrade, and it is not this fix
Collabora’s October 15 post says that moving to a current release also brings Landlock, a Linux security module that lets a process restrict itself to a list of files. They call it an extra benefit of upgrading. They do not call it the patch for CVE-2026-110447.
It would be the wrong layer even if it had been on earlier. Landlock applies to a process that opts in, or to a supervisor that puts a process in it. The command injection runs in the PHP interpreter, as the web server user, at the moment that interpreter decides to start coolwsd. A sandbox around the editor starts later, and only around the editor. The September 14 process list is the illustration: the shell metacharacters were already inside the editor’s command line, because they had been part of the string that launched it.
If this app is on a server you run
- In Nextcloud’s apps list, look for Collabora Online - Built-in CODE Server, including the ARM64 variant. If the version is below 26.4.303, upgrade it or remove it. If the Nextcloud itself is version 29 or older, the advisory says to upgrade Nextcloud or remove the app. Turning the app off in the menu leaves
proxy.phpon disk. - If that app was installed below 26.4.303 at any point from September 10 onward, look in
apps/richdocumentscode/for PHP files that do not belong to the app. The name pattern Meeks told operators to remove isshx*.php. Upgrading does not delete a file an intruder already wrote. - In the web server’s access log, look for requests to
proxy.phpwhose path is not the normal app path, and for status requests you did not send. A hit is a reason to do the file check. It is not, by itself, proof the start branch ran. - If a shell was there, rotate the secrets the web server account could read. That includes the database password and the instance secret in
config/config.php, and the credentials of anything else that user could open. Deleting the PHP file does not unread a file the shell already opened. - For documents in the browser after that, Collabora’s recommended installs are a separate server: their Docker image, a distribution package, or Nextcloud All-in-One. Those are the installs this CVE does not cover.
Sources
- GHSA-g3vx-3m76-fghh, Collabora, October 14, 2026.
- Stay safe: upgrade everything regularly, Collabora, October 15, 2026.
- richdocumentscode issue 354, opened September 11, 2026.
- Compare 26.4.302 and 26.4.303.
- To Collabora built-in user: update ASAP, Nextcloud forum, October 3, 2026.
- Hackers exploit Collabora RCE flaw to backdoor Nextcloud servers, Bill Toulas, BleepingComputer, October 15, 2026.
- Hackers backdoor Nextcloud servers, The Hacker News, October 2026.
- GHSA-f97p-r72q-64h2, GitHub Advisory Database.
- CERT Santé notice, October 14, 2026.
New posts, by email.
About once a month. Plain-language privacy notes, nothing else. I never share your address.