GitHub Advisoryadvisory · PyPI
GHSA-hxpf-9xvq-wph8 netlicensing-mcp: REST Path Traversal Bypasses Token Redaction
CRITICAL
Official page ↗
- Aliases
- CVE-2026-57496
- Ecosystem
- PyPI
- Packages
- netlicensing-mcp
- Severity
- Critical
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N
- Weaknesses
- CWE-22
- Reviewed
- 2026-06-18
Affected packages
• PyPI netlicensing-mcp: < 0.1.8 → fixed in 0.1.8
Description
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`
```python
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`
```python
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:143` — `url = 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-239` — `redact_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)
```bash
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
```bash
cd /path/to/Labs64__NetLicensing-MCP
PYTHONPATH=src python3 - 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) 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`
```d…
Related
Alias · CVE (1)
- CVE-2026-57496 NetLicensing MCP Server is a natural-language interface that enables agentic applications to manage the software-licensing lifecycle in… vulnerability
Weakness · CWE (1)
- CWE-22 Improper Limitation of a Pathname to a Restricted Directory weakness
References
- https://github.com/Labs64/NetLicensing-MCP/security/advisories/GHSA-hxpf-9xvq-wph8 web
- https://nvd.nist.gov/vuln/detail/CVE-2026-57496 advisory
- https://github.com/Labs64/NetLicensing-MCP/pull/6 web
- https://github.com/Labs64/NetLicensing-MCP/commit/b8fd0ea76d533202573eb24add9fb2fbd9331496 web
- https://github.com/Labs64/NetLicensing-MCP package
- https://github.com/Labs64/NetLicensing-MCP/releases/tag/0.1.8 web
- https://github.com/pypa/advisory-database/tree/main/vulns/netlicensing-mcp/PYSEC-2026-3489.yaml web