netlicensing-mcp: REST Path Traversal Bypasses Token Redaction
### 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
- Products
- netlicensing-mcp
- Affected versions
- 0.0.6, 0.1.0, 0.1.1, 0.1.2, 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7
- Fixed versions
- 0.1.8
- CVEs
- CVE-2026-57496
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 30 Oct 2026, 19:06 UTC · Revision 1
Source evidence
netlicensing-mcp: REST Path Traversal Bypasses Token Redaction
core-osv · Original sourcePublished 18 Jun 2026, 17:22 UTC
### 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
osv:GHSA-hxpf-9xvq-wph8
netlicensing-mcp
Fixed versions: 0.1.8
Complete source record
{
"id": "65caac95af58a9997daa4639e62d08309b0d5bd2cdf8df8ffe6b1c82cd2161b5",
"url": "https://osv.dev/vulnerability/GHSA-hxpf-9xvq-wph8",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "netlicensing-mcp: REST Path Traversal Bypasses Token Redaction",
"summary": "### 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",
"evidence": "osv:GHSA-hxpf-9xvq-wph8",
"products": [
{
"name": {
"value": "netlicensing-mcp",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "0.1.8",
"evidence": "/affected/0/ranges"
}
],
"affected_versions": [
{
"value": "0.0.6",
"evidence": "/affected/0/versions"
},
{
"value": "0.1.0",
"evidence": "/affected/0/versions"
},
{
"value": "0.1.1",
"evidence": "/affected/0/versions"
},
{
"value": "0.1.2",
"evidence": "/affected/0/versions"
},
{
"value": "0.1.3",
"evidence": "/affected/0/versions"
},
{
"value": "0.1.4",
"evidence": "/affected/0/versions"
},
{
"value": "0.1.5",
"evidence": "/affected/0/versions"
},
{
"value": "0.1.6",
"evidence": "/affected/0/versions"
},
{
"value": "0.1.7",
"evidence": "/affected/0/versions"
}
]
}
],
"severity": "critical",
"structured": {
"id": "GHSA-hxpf-9xvq-wph8",
"aliases": [
"CVE-2026-57496",
"GHSA-hxpf-9xvq-wph8",
"PYSEC-2026-3489"
],
"metrics": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N"
}
],
"affected": [
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "0.1.8"
}
]
}
],
"package": {
"name": "netlicensing-mcp",
"purl": "pkg:pypi/netlicensing-mcp",
"ecosystem": "PyPI"
},
"versions": [
"0.0.6",
"0.1.0",
"0.1.1",
"0.1.2",
"0.1.3",
"0.1.4",
"0.1.5",
"0.1.6",
"0.1.7"
],
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-hxpf-9xvq-wph8/GHSA-hxpf-9xvq-wph8.json"
}
}
],
"modified": "2026-10-15T18:45:10.600088359Z",
"provider": "osv",
"references": [
"https://github.com/Labs64/NetLicensing-MCP/security/advisories/GHSA-hxpf-9xvq-wph8",
"https://nvd.nist.gov/vuln/detail/CVE-2026-57496",
"https://github.com/Labs64/NetLicensing-MCP/pull/6",
"https://github.com/Labs64/NetLicensing-MCP/commit/b8fd0ea76d533202573eb24add9fb2fbd9331496",
"https://github.com/Labs64/NetLicensing-MCP",
"https://github.com/Labs64/NetLicensing-MCP/releases/tag/0.1.8",
"https://github.com/pypa/advisory-database/tree/main/vulns/netlicensing-mcp/PYSEC-2026-3489.yaml"
],
"provider_metadata": {
"cwe_ids": [
"CWE-22"
],
"severity": "CRITICAL",
"github_reviewed": true,
"nvd_published_at": null,
"github_reviewed_at": "2026-06-18T17:22:02Z"
}
},
"related_cves": [
{
"value": "CVE-2026-57496",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/database_specific/severity"
},
"source_id": "core-osv",
"document_id": 335637,
"published_at": "2026-06-18T17:22:02+00:00"
}