Your Nextcloud's optional document editor has a back door that opens every time the server blinks
CVE-2026-110447 is an unauthenticated OS command injection in proxy.php within the richdocumentscode Nextcloud app (Collabora Online Built-in CODE Server) affecting all versions before 26.4.303. When the embedded CODE server process is not running — a transient state triggered by container restarts, upgrades, crashes, or resource pressure — crafted HTTP GET requests to /apps/richdocumentscode/proxy.php?status pass attacker-controlled input through the remote_font_config.url parameter into a shell invocation of Collabora_Online.AppImage. Shell command substitution via $() and ${IFS} whitespace obfuscation gives the attacker arbitrary OS command execution as the www-data web server user. Standalone Collabora Online Docker/RPM/DEB deployments and Nextcloud All-in-One are not affected — only the optional built-in CODE app.
The GitHub Security Advisory (GHSA-f97p-r72q-64h2) carries a CVSS 4.0 score of 9.2, which is appropriate for the unauthenticated-network-RCE mechanics but slightly generous given the AT:P (attack-timing prerequisite) condition requiring the CODE server to be stopped. In practice, however, this friction point has been completely overcome by real-world attackers who began exploiting this flaw on September 10, 2026 — one day after the fix was committed and one day before v26.4.303 shipped — a full 34 days before the CVE was even published on October 14. Attackers are deploying PHP web shells (shx*.php, shrf*.php) and using them to harvest password databases, password manager vaults (Bitwarden, 1Password, *.kdbx), and cryptocurrency wallets. The gap between severity label and reality here is the opposite of the usual story: the *timing* condition that the CVSS vector encodes as friction is trivially defeated by continuous scanning, and the execution-as-www-data limitation understates impact because www-data owns every file in the Nextcloud data directory plus config.php (which contains the database password).
5 steps from start to impact.
Discover internet-facing Nextcloud with richdocumentscode
/apps/richdocumentscode/proxy.php. Nextcloud is commonly deployed internet-facing as a self-hosted cloud platform; the richdocumentscode app is an optional but popular add-on for integrated document editing. Shodan and FOFA queries for Nextcloud headers combined with path probing identify candidates.- Target Nextcloud instance is internet-reachable
- richdocumentscode app is installed (any version < 26.4.303)
- richdocumentscode is optional — not every Nextcloud instance has it
- Some deployments use standalone Collabora (Docker/RPM) which is unaffected
/apps/richdocumentscode/proxy.php?status — unusual in normal operation.Wait for or induce CODE server downtime
- CODE server must be in a stopped state when the request arrives
- Well-configured containers with fast restart reduce the window
- Health-check orchestration (Kubernetes liveness probes) can minimize downtime
proxy.php?status in access logs indicate polling/scanning behavior.Inject OS command via proxy.php
proxy.php?status with shell metacharacters — specifically $() command substitution and ${IFS} whitespace obfuscation — embedded in the remote_font_config.url parameter. When the CODE server is offline, proxy.php passes this unsanitized input to a sh invocation while attempting to launch Collabora_Online.AppImage. The injected command executes as the www-data user. No authentication or session token is required.- Steps 1 and 2 conditions met
- Network path to the Nextcloud HTTP(S) port is open
- WAF rules inspecting for
$()and${IFS}patterns in URL parameters can block the payload - CSP and request-body inspection won't help — this is a GET parameter injection
Deploy PHP web shell for persistence
shx*.php, shrf*.php) into the /apps/richdocumentscode/ directory, which is web-accessible. This gives the attacker persistent command execution that survives CODE server restarts, decoupling their access from the transient exploitation window. The web shell runs with the same www-data privileges.- Step 3 succeeds
- Web server user has write access to the app directory (default)
- Read-only filesystem mounts for the app directory would prevent shell drop
- File integrity monitoring (AIDE, OSSEC, Wazuh) on the Nextcloud directory tree would alert
.php files in /apps/richdocumentscode/. EDR detecting www-data spawning sh or writing PHP files.Exfiltrate credentials and sensitive data
*.kdbx, Bitwarden/1Password vaults), cryptocurrency wallet files (wallet.dat, keystore.json), and the Nextcloud config.php file which contains database credentials. The www-data user has read access to the entire Nextcloud data directory, giving the attacker access to every file every user has stored. Database credentials from config.php may enable lateral movement to the database server.- Persistent web shell from Step 4
- Nextcloud data directory readable by www-data (default)
- Database on a separate host with firewall rules limits lateral pivot
- Encrypted-at-rest Nextcloud storage with user-key encryption limits data exposure
find commands searching for *.kdbx, wallet.dat, config.php reads by web shell processes. Database audit logs showing new connections from the web server.proxy.php exploitable). Check for IOCs before and after: look for shx*.php and shrf*.php files in the app directory and audit www-data process trees.deny rule in your reverse proxy (nginx, Apache, Caddy, HAProxy) or WAF for the path /apps/richdocumentscode/proxy.php. This breaks the attack chain at Step 3 by preventing the malicious request from reaching the vulnerable endpoint. This is a same-day emergency mitigation while you schedule the update. Note: this will break Collabora document editing functionality until the patch is applied.$(), backtick command substitution, and ${IFS} patterns in URL parameters. This provides defense-in-depth against the specific payload pattern but is bypassable with encoding variations. Deploy within 3 days per noisgate mitigation SLA./apps/richdocumentscode/ read-only at the filesystem level prevents web shell persistence (Step 4). The initial command injection still fires, but the attacker cannot write a persistent PHP shell. This limits exploitation to the transient window and prevents the most damaging post-exploitation pattern observed in the wild..php files in the Nextcloud directory tree, especially under /apps/. This does not prevent exploitation but detects web shell drops within minutes, enabling rapid incident response. Alert on any new .php file creation by the www-data user.- Disabling the app in Nextcloud admin settings — this only removes the app from the Nextcloud UI and routing table. The
proxy.phpfile remains on the filesystem and is still directly accessible via HTTP. Multiple admin reports confirm exploitation after disabling. - Network-level IP allowlisting for Nextcloud — while restricting access to known IPs would help, Nextcloud is typically deployed as an internet-facing file-sharing platform. Restricting access defeats the product's purpose and is not practical for most deployments.
- PHP
disable_functionsfor shell_exec/exec — the injection occurs throughCollabora_Online.AppImageinvocation, not through PHP'sshell_exec(). The shell is invoked by the AppImage binary, not by PHP's command execution functions directly. - Nextcloud brute-force protection / rate limiting — irrelevant because the attack requires no authentication. Rate limiting on login endpoints does not protect
proxy.php.
The supporting signals.
| In-the-Wild Exploitation | CONFIRMED ACTIVE since September 10, 2026. Attackers deployed PHP web shells on production Nextcloud servers, harvested credentials and crypto wallets. Exploitation began 34 days before the CVE was published. Multiple community reports on the Nextcloud forum (Oct 3) and covered by BleepingComputer, The Hacker News, and CybersecurityNews. |
|---|---|
| Proof-of-Concept | Public PoC available on GitHub: adriyansyah-mf/cve-2026-110447 — actively being forked. Indexed on pocindex.io and tracked in SecureWithUmer/CVE-2026-PoCs. Payload uses $() command substitution and ${IFS} obfuscation against proxy.php?status. |
| EPSS Score | 1.225% (68th percentile) — notably low given confirmed active exploitation. EPSS is lagging the real-world signal here; treat this as an undercount. |
| CISA KEV Status | Not listed as of 2026-10-19. Given confirmed exploitation, KEV addition is likely imminent. The product's limited enterprise footprint compared to Microsoft/Cisco may delay listing. |
| CVSS 4.0 Vector | 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 — 9.2. AV:N/PR:N/UI:N = unauthenticated remote. AT:P reflects the requirement for CODE server to be stopped. All impact metrics High. |
| Affected Versions | richdocumentscode < 26.4.303 (the Nextcloud 'Built-in CODE Server' app). Standalone Collabora Online (Docker, RPM, DEB, Nextcloud AIO) is NOT affected. This is a Nextcloud-app-specific deployment path only. |
| Fixed Version | 26.4.303 — released September 11, 2026. Fix committed September 9. Available via the Nextcloud App Store. Note: simply *disabling* the app in Nextcloud settings does NOT remediate — the vulnerable proxy.php remains on the filesystem. Must update or fully remove the app from disk. |
| Scanning / Exposure | Nextcloud instances are commonly internet-facing (self-hosted cloud use case). No specific Shodan/Censys tag for richdocumentscode exists, but Nextcloud instances are readily enumerable. The richdocumentscode app is an *optional* add-on — not all Nextcloud instances are vulnerable. |
| Disclosure Timeline | Sept 9: Fix committed. Sept 10: Exploitation begins (0-day window). Sept 11: v26.4.303 released. Oct 3: Community forum warning. Oct 14: CVE published, GHSA-f97p-r72q-64h2 advisory issued. The 34-day gap between exploitation start and CVE publication is concerning. |
| Researcher / Discovery | No individual researcher credited. Discovery appears to be community-driven after administrators found web shells on compromised servers. The delayed CVE publication was attributed to GitHub advisory processing backlogs. |
Sources.
- BleepingComputer — Hackers exploit Collabora RCE flaw to backdoor Nextcloud servers
- GitHub Advisory GHSA-f97p-r72q-64h2
- SecurityOnline — CVE-2026-110447 Actively Exploited
- DEV Community — Pre-Authentication OS Command Injection Technical Analysis
- CybersecurityNews — Hackers Exploit Critical Collabora Online Flaw
- CVEFeed.io — CVE-2026-110447 Detail
- PoC Repository — adriyansyah-mf/cve-2026-110447
- Aviatrix Threat Research — Nextcloud Collabora Web Shell Backdoor Attack
Why this verdict
- Pre-auth RCE with zero interaction: The attack requires no credentials, no user interaction, and works over the network.
AV:N/PR:N/UI:Nis the most dangerous access profile. The only gate is a transient server-state condition — and attackers have proven they can clear it. - Active exploitation since September 10, 2026: This is not theoretical. PHP web shells are being planted on production Nextcloud servers *right now*. The exploitation campaign predates the CVE by 34 days. Any friction-based downgrade is overridden by the demonstrated real-world attack chain. EPSS at 1.225% is a lagging indicator that understates the threat.
- Public PoC lowers the bar further: The adriyansyah-mf/cve-2026-110447 repository provides a ready-made exploit that is actively being forked. This eliminates the skill barrier for copycat attacks.
- www-data = full Nextcloud compromise: While execution is not as root, the
www-datauser owns the entire Nextcloud data directory (every user's files),config.php(database credentials), and can write web shells for persistence. In practice this is a complete application-tier compromise. - Role multiplier: Nextcloud is not in the canonical high-value infrastructure catalog (not AD, not a hypervisor, not PKI). However, in its *typical deployment role* as an enterprise file-sharing platform, it stores sensitive documents, credentials, and business data for the entire organization. A compromise of the Nextcloud data tier is functionally equivalent to a mass data breach. In deployments where Nextcloud is integrated with LDAP/AD via SSO, the database credentials in
config.phpmay provide a pivot path to directory services. The blast radius is host-to-tenant scale (all Nextcloud users' data), not fleet-scale. This sets the floor at HIGH; the confirmed active exploitation and pre-auth RCE push it to CRITICAL. - Disabling the app does not remediate: A common admin response — disabling the app in Nextcloud settings — leaves
proxy.phpon the filesystem and exploitable. This false sense of security amplifies the real-world risk.
Why not higher?
The score is already CRITICAL at 9.0. A 10.0 would require no preconditions at all. The AT:P condition (CODE server must be stopped) is a genuine, if overcomable, friction point that prevents always-on exploitation. Execution as www-data rather than root limits immediate OS-level impact — the attacker owns the application but must escalate to own the host kernel. The vulnerability also only affects the optional richdocumentscode app, not all Nextcloud instances.
Why not lower?
Downgrading below CRITICAL would require ignoring the confirmed active exploitation campaign that has been running for over five weeks. The attack chain is proven, the PoC is public, and web shells are being deployed on real servers. The transient-state requirement sounds like meaningful friction on paper, but attackers have demonstrated it is trivially defeated by continuous polling. Any enterprise running richdocumentscode < 26.4.303 on an internet-facing Nextcloud should treat this as an emergency.
Crowdsourced verification payload.
Run this script on the Nextcloud host as root or the www-data user. Pass the Nextcloud web root as the first argument. Example: sudo bash check_cve_2026_110447.sh /var/www/nextcloud. The script checks whether the vulnerable app is installed, its version, and scans for known web shell IOCs. No network access or special packages required beyond grep, find, and sort.
#!/usr/bin/env bash
# CVE-2026-110447 Checker — richdocumentscode OS Command Injection
# Exit codes: 0 = PATCHED/not-installed, 1 = VULNERABLE, 2 = UNKNOWN
set -uo pipefail
NC_ROOT="${1:-/var/www/nextcloud}"
FIXED_VER="26.4.303"
RESULT="UNKNOWN"
if [[ ! -d "$NC_ROOT" ]]; then
echo "[!] Nextcloud root not found at $NC_ROOT"
echo "UNKNOWN"
exit 2
fi
# Locate richdocumentscode in either app directory
TARGET=""
for d in "$NC_ROOT/apps/richdocumentscode" "$NC_ROOT/custom_apps/richdocumentscode"; do
[[ -d "$d" ]] && TARGET="$d" && break
done
if [[ -z "$TARGET" ]]; then
echo "[*] richdocumentscode app not found — this host is NOT affected."
echo "PATCHED"
exit 0
fi
# Parse installed version
INFO="$TARGET/appinfo/info.xml"
if [[ ! -f "$INFO" ]]; then
echo "[!] Cannot find $INFO — manual inspection needed."
echo "UNKNOWN"
exit 2
fi
VER=$(grep -oP '<version>\K[^<]+' "$INFO" 2>/dev/null || true)
if [[ -z "$VER" ]]; then
echo "[!] Could not parse version from $INFO"
echo "UNKNOWN"
exit 2
fi
echo "[*] richdocumentscode installed at: $TARGET"
echo "[*] Installed version: $VER"
echo "[*] Fixed version: $FIXED_VER"
# Compare versions (sort -V)
LOWEST=$(printf '%s\n' "$VER" "$FIXED_VER" | sort -V | head -n1)
if [[ "$VER" == "$FIXED_VER" || "$LOWEST" == "$FIXED_VER" ]]; then
RESULT="PATCHED"
echo "[+] VERSION CHECK: PATCHED ($VER >= $FIXED_VER)"
else
RESULT="VULNERABLE"
echo "[!] VERSION CHECK: VULNERABLE ($VER < $FIXED_VER)"
fi
# IOC scan
echo ""
echo "--- IOC Scan (known web shell patterns) ---"
IOC=0
for pat in 'shx*.php' 'shrf*.php'; do
HITS=$(find "$TARGET" -name "$pat" -type f 2>/dev/null)
if [[ -n "$HITS" ]]; then
echo "[!!] WEBSHELL INDICATOR: $HITS"
IOC=1
fi
done
# Check for any .php files newer than info.xml (rogue drops)
ROGUE=$(find "$TARGET" -name '*.php' -newer "$INFO" -type f 2>/dev/null \
| grep -vE '/(proxy|index|ajax|wopi|fonts)\.php$' || true)
if [[ -n "$ROGUE" ]]; then
echo "[!!] SUSPICIOUS PHP files newer than info.xml:"
echo "$ROGUE"
IOC=1
fi
if [[ $IOC -eq 0 ]]; then
echo "[+] No known IOCs found."
else
echo "[!!] IOCs DETECTED — initiate incident response immediately."
fi
echo ""
echo "$RESULT"
[[ "$RESULT" == "VULNERABLE" ]] && exit 1
[[ "$RESULT" == "UNKNOWN" ]] && exit 2
exit 0