Threat Overview
On 14 October 2026, Collabora published a critical advisory for CVE-2026-110447 (CVSS v4.0 9.2), an unauthenticated OS command injection in proxy.php of the optional Nextcloud Collabora Online – Built-in CODE Server app (richdocumentscode). The vulnerable code can execute a shell command as the web-server user when the local CODE service is not running, such as after restart, upgrade, or crash. Collabora’s public issue tracker records attacks beginning 10 September 2026 against version 26.4.302. Administrators documented specially crafted URL paths containing shell command substitution, ${IFS} whitespace substitution, Base64 decoding, and creation of shx*.php webshells under the richdocumentscode app directory. One affected server showed follow-on commands searching for credential vaults and cryptocurrency wallet files; that does not establish exfiltration. The vulnerability is distinct from CVE-2025-66208. The fixed app version 26.4.303 shipped 11 September; the coordinated public advisory was issued 14 October.
References
- Collabora security advisory GHSA-g3vx-3m76-fghh (14 Oct 2026): https://github.com/CollaboraOnline/online/security/advisories/GHSA-g3vx-3m76-fghh
- CollaboraOnline issue #354: observed attacks and webshells (11 Sep onward): https://github.com/CollaboraOnline/richdocumentscode/issues/354
- NVD CVE-2026-110447 (14 Oct 2026): https://nvd.nist.gov/vuln/detail/CVE-2026-110447
- BleepingComputer report (15 Oct 2026): https://www.bleepingcomputer.com/news/security/hackers-exploit-collabora-rce-flaw-to-backdoor-nextcloud-servers/
Impacted Systems
- Vendor/product: Collabora Online – Built-in CODE Server (
richdocumentscode) Nextcloud app only, typically self-hosted Nextcloud with the optional embedded CODE AppImage component. - Affected versions:
richdocumentscodebefore 26.4.303, including confirmed vulnerable 26.4.302. Fixed: 26.4.303 or later (released 11 Sep 2026). - OS/deployment: Self-hosted Nextcloud web/PHP host, commonly Linux; the attack executes as the web-server account. The vendor says Nextcloud 29 and older are end-of-life and should be upgraded or the app removed.
- Prerequisite: Remote HTTP access to vulnerable
proxy.phpwhile the embedded CODE server is not running. The URL path is typically under/apps/richdocumentscode/proxy.php; externally exposed Nextcloud increases risk. Port is determined by the Nextcloud web deployment (commonly HTTPS/443, not an exploit requirement). - Unaffected: Standalone Collabora Online server deployments, and Nextcloud environments not using the optional built-in CODE app. Merely disabling a vulnerable installed app is not sufficient; upgrade or remove it. This CVE is not CVE-2025-66208.
Why this matters
Nextcloud is often exposed to the Internet and stores business documents and integration credentials. The reported command injection permits webshell persistence and access to data readable by the PHP/web-server account. A late advisory relative to the patch release increases the likelihood of unrecognized exposure.
Exploitation Status
Confirmed exploitation. Public maintainer issue and independent administrators documented webshell creation and follow-on commands in September 2026; the 14 October CVE record explicitly states exploitation in September and October. The exact total of compromised installations is unknown. No root-level escalation or confirmed bulk exfiltration is established by these sources.
What this hunt looks for
Prepared Sentinel queries for command-injection URL patterns, webshell access, Linux web access Syslog fallback, web process-to-shell execution, PHP file creation in the app, reported inbound source IPs/webhook callbacks, and rare outbound traffic from web processes. These queries have not been executed in a specific customer workspace.
Required logs
Hunts target only Microsoft Sentinel-ingested HTTP/WAF events in CommonSecurityLog, forwarded web-server Syslog, and Defender Device* telemetry from monitored Nextcloud hosts. Generic firewall flows without full request paths cannot reveal the injection. Host file artifacts and process ancestry require Linux EDR/audit onboarding. No match cannot clear unmonitored web servers or non-ingested Apache/Nginx logs.
Hunt 01 — First pass — exploitation requests against richdocumentscode proxy.php
CommonSecurityLog
| where TimeGenerated >= ago(45d)
| extend Url=tostring(column_ifexists('RequestURL','')), Msg=tostring(column_ifexists('Message',''))
| where Url contains 'richdocumentscode' and Url contains 'proxy.php'
| where Url contains '%24%28' or Url contains '%2e%2e' or Url contains '${IFS}' or Url contains 'base64' or Url contains '$(echo' or Msg contains '${IFS}' or Msg contains 'base64' or Msg contains '$(echo'
| project TimeGenerated, DeviceVendor, DeviceProduct, SourceIP, DestinationIP, DestinationPort, DeviceAction, Url, Msg
| order by TimeGenerated descHunt 02 — Web requests — attempted or established shx PHP webshell access
CommonSecurityLog
| where TimeGenerated >= ago(45d)
| extend Url=tostring(column_ifexists('RequestURL','')), Msg=tostring(column_ifexists('Message',''))
| where (Url contains 'richdocumentscode' and Url contains '/shx' and Url contains '.php') or (Msg contains 'richdocumentscode' and Msg contains 'shx' and Msg contains '.php')
| project TimeGenerated, SourceIP, DestinationIP, DestinationPort, DeviceAction, Url, Msg
| order by TimeGenerated descHunt 03 — Linux web-access Syslog fallback — encoded command substitution
Syslog
| where TimeGenerated >= ago(45d)
| where SyslogMessage contains 'richdocumentscode' and SyslogMessage contains 'proxy.php'
| where SyslogMessage contains '%24%28' or SyslogMessage contains '%2e%2e' or SyslogMessage contains '${IFS}' or SyslogMessage contains 'base64' or SyslogMessage contains '$(echo'
| project TimeGenerated, Computer, ProcessName, SyslogMessage
| order by TimeGenerated descHunt 04 — Linux web process — PHP/Apache spawning shell and download utilities
DeviceProcessEvents
| where TimeGenerated >= ago(45d)
| where InitiatingProcessFileName in~ ('php-fpm','php-fpm8.3','php-fpm8.2','php','apache2','httpd','nginx')
| where FileName in~ ('sh','bash','curl','wget','python','python3','perl','base64')
| project TimeGenerated, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine, FolderPath
| order by TimeGenerated descHunt 05 — Webroot files — new PHP scripts in the richdocumentscode application
DeviceFileEvents
| where TimeGenerated >= ago(45d)
| where FolderPath contains 'richdocumentscode'
| where FileName endswith '.php'
| where ActionType in~ ('FileCreated','FileModified','FileRenamed')
| project TimeGenerated, DeviceName, ActionType, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine, SHA256
| order by TimeGenerated descHunt 06 — Network — published inbound attack source or webhook callbacks
let AttackerIPs=dynamic(['139.28.18.122','89.38.98.50']);
CommonSecurityLog
| where TimeGenerated >= ago(45d)
| extend Url=tostring(column_ifexists('RequestURL',''))
| where SourceIP in (AttackerIPs) or Url contains 'webhook.site'
| project TimeGenerated, DeviceVendor, DeviceProduct, SourceIP, DestinationIP, DestinationPort, DeviceAction, Url, Message
| order by TimeGenerated descHunt 07 — Rare outbound connections from PHP or web-server processes
let WebProcesses=dynamic(['php-fpm','php-fpm8.3','php-fpm8.2','php','apache2','httpd','nginx']);
let Recent=DeviceNetworkEvents
| where TimeGenerated >= ago(7d)
| where InitiatingProcessFileName in~ (WebProcesses)
| where isnotempty(RemoteIP) and not(ipv4_is_private(RemoteIP))
| summarize Hits=count(), LastSeen=max(TimeGenerated), Urls=make_set(RemoteUrl,10) by DeviceName, RemoteIP, InitiatingProcessFileName;
let Baseline=DeviceNetworkEvents
| where TimeGenerated between (ago(37d)..ago(7d))
| where InitiatingProcessFileName in~ (WebProcesses)
| summarize by DeviceName, RemoteIP;
Recent
| join kind=leftanti Baseline on DeviceName, RemoteIP
| order by Hits descDetection Notes
- Highest signal: Query 01 (
proxy.phpplus shell metacharacters), query 02 (shx*.phpwebshell calls), query 05 (new PHP in the app directory). Query 04 process ancestry is strong only when scoped to the Nextcloud host. - Encoded paths: WAFs may decode
%2e%2eand%24%28or truncate long URLs. Query 01 uses multiple alternatives but cannot capture every encoding variant. - Status codes: HTTP 200 alone is not proof of exploitation; correlate suspicious requests with webshell creation or command execution. An observed blocked request establishes only an attempt.
- Network indicators:
139.28.18.122and89.38.98.50were reported by administrators, not universal attacker infrastructure.webhook.siteis a legitimate testing service; require correlation to Nextcloud and exploit requests. - Visibility gaps: Native Nextcloud app version and CODE process state are not reliably inferable from Sentinel unless asset/application inventory is ingested. No EDR on Linux means webshell files and child-process behavior are not visible in Device* tables.
- Do not conflate deployments: Standalone Collabora, separate Docker Collabora, and
richdocumentswithout the built-in CODE app are outside this vulnerability scope.