{"id":"CVE-2026-123810","aliases":["EUVD-2026-120444","GHSA-pqh8-p93p-2rx7"],"status":"published","title":"Dynatrace MCP Server: DQL injection via parameters not documented as DQL","description":"Dynatrace MCP Server is an MCP server for Dynatrace Observability. Prior to 2.1.1, several read capabilities interpolate caller-controlled values into DQL without sufficient validation or escaping. The src/capabilities/find-monitored-entity-by-name.ts capability embeds entityNames in string searches, src/capabilities/list-problems.ts, src/capabilities/list-vulnerabilities.ts, and src/capabilities/list-exceptions.ts embed timeframe values, and src/capabilities/get-events-for-cluster.ts embeds timeframe, clusterId, and kubernetesEntityId. Crafted values can close string literals, append pipeline stages, or comment out the remaining intended query, allowing callers to bypass field selection, time-window, and result-display limits in tools marked readOnlyHint. The issue does not grant data access beyond the configured token's existing execute_dql capability, but it breaks the narrower auto-approved tool contract. This issue is fixed in version 2.1.1.","severity":{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00229,"percentile":0.13803,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-89","CWE-943"],"published":"2026-07-31T15:56:12Z","modified":"2026-11-10T16:14:03Z","fixes":[{"ecosystem":"npm","package":"@dynatrace-oss/dynatrace-mcp-server","fixed_in":["2.1.1"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"@dynatrace-oss/dynatrace-mcp-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.1.1"}]}]},{"source":"osv","ecosystem":"npm","package":"@dynatrace-oss/dynatrace-mcp-server","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.1.1"}]}]}],"products":[{"vendor":"dynatrace-oss","product":"dynatrace-mcp"}],"references":[{"url":"https://github.com/dynatrace-oss/dynatrace-mcp/security/advisories/GHSA-pqh8-p93p-2rx7","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/dynatrace-oss/dynatrace-mcp/commit/15d3546c0618ffbaeaeca477337e08e92f2151bc","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/dynatrace-oss/dynatrace-mcp/releases/tag/v2.1.1","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/dynatrace-oss/dynatrace-mcp/pull/562","tags":["web"]},{"url":"https://github.com/advisories/GHSA-pqh8-p93p-2rx7"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/123xxx/CVE-2026-123810.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-123810","tags":["advisory"]},{"url":"https://github.com/dynatrace-oss/dynatrace-mcp","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-123810","title":"Dynatrace MCP Server: DQL injection via parameters not documented as DQL","description":"Dynatrace MCP Server is an MCP server for Dynatrace Observability. Prior to 2.1.1, several read capabilities interpolate caller-controlled values into DQL without sufficient validation or escaping. The src/capabilities/find-monitored-entity-by-name.ts capability embeds entityNames in string searches, src/capabilities/list-problems.ts, src/capabilities/list-vulnerabilities.ts, and src/capabilities/list-exceptions.ts embed timeframe values, and src/capabilities/get-events-for-cluster.ts embeds timeframe, clusterId, and kubernetesEntityId. Crafted values can close string literals, append pipeline stages, or comment out the remaining intended query, allowing callers to bypass field selection, time-window, and result-display limits in tools marked readOnlyHint. The issue does not grant data access beyond the configured token's existing execute_dql capability, but it breaks the narrower auto-approved tool contract. This issue is fixed in version 2.1.1.","status":"published","published":"2026-11-09T20:59:50.956Z","modified":"2026-11-10T16:14:03.628Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-89"],"updated_at":"2026-11-10T17:39:35.624694Z"}],"euvd":[{"id":"EUVD-2026-120444","description":"Dynatrace MCP Server is an MCP server for Dynatrace Observability. Prior to 2.1.1, several read capabilities interpolate caller-controlled values into DQL without sufficient validation or escaping. The src/capabilities/find-monitored-entity-by-name.ts capability embeds entityNames in string searches, src/capabilities/list-problems.ts, src/capabilities/list-vulnerabilities.ts, and src/capabilities/list-exceptions.ts embed timeframe values, and src/capabilities/get-events-for-cluster.ts embeds timeframe, clusterId, and kubernetesEntityId. Crafted values can close string literals, append pipeline stages, or comment out the remaining intended query, allowing callers to bypass field selection, time-window, and result-display limits in tools marked readOnlyHint. The issue does not grant data access beyond the configured token's existing execute_dql capability, but it breaks the narrower auto-approved tool contract. This issue is fixed in version 2.1.1.","status":"published","published":"2026-11-09T20:59:50Z","modified":"2026-11-10T16:14:03Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","level":"medium"}],"updated_at":"2026-11-09T22:18:21.971974Z"}],"ghsa":[{"id":"GHSA-pqh8-p93p-2rx7","title":"@dynatrace-oss/dynatrace-mcp-server has a DQL injection via parameters not documented as DQL","description":"### Summary\nA DQL injection vulnerability in several read tools lets a caller bypass the tools' documented field-scope, time-window, and display caps by injecting DQL pipeline stages through parameters typed as identifiers.\n\n### Details\nSeveral tools interpolate caller-supplied parameters directly into DQL query strings without quoting or escaping. The affected parameters are documented in their Zod schemas as identifiers or constrained shorthand (such as `\"24h\"` timeframe values or Kubernetes UIDs) - not as DQL expressions. The interpolation lets a caller break out of string literals, append arbitrary DQL pipeline stages, and use `//` line comments (documented in the [Dynatrace DQL language reference](https://docs.dynatrace.com/docs/discover-dynatrace/platform/grail/dynatrace-query-language/dql-reference)) to discard the rest of the intended query.\n\nThe marginal-privilege ceiling is low because the operator's token also exposes `execute_dql` with full DQL access. What the injection grants is the ability to bypass the affected tools' contract: the `readOnlyHint: true` annotation that MCP clients may treat as a signal to auto-approve, the per-tool field selection (e.g., `| fields id, name, type`), the display caps (`maxProblemsToDisplay`, `maxVulnerabilitiesToDisplay`, `maxEntitiesToDisplay`), and the time-window bounds.\n\nThe vulnerable interpolations are:\n\n| File | Line | Parameter | Interpolation |\n|------|------|-----------|---------------|\n| `src/capabilities/find-monitored-entity-by-name.ts` | 23 | `entityNames[]` | `` `fetch ${entityType} \\| search \"*${entityNames.join('*\" OR \"*')}*\" \\| fieldsAdd entity.type \\| expand tags` `` |\n| `src/capabilities/find-monitored-entity-by-name.ts` | 41 | `entityNames[]` | `` `smartscapeNodes \"*\" \\| search \"*${entityNames.join('*\" OR \"*')}*\" \\| fields id, name, type` `` |\n| `src/capabilities/list-problems.ts` | 27 | `timeframe` | `` `fetch dt.davis.problems, from: now()-${timeframe}, to: now()` `` |\n| `src/capabilities/list-vulnerabilities.ts` | 19 | `timeframe` | `` `fetch security.events, from: now()-${timeframe}, to: now()` `` |\n| `src/capabilities/list-exceptions.ts` | 11 | `timeframe` | `` `fetch user.events, from: now()-${timeframe}, to: now()` `` |\n| `src/capabilities/get-events-for-cluster.ts` | 20 | `timeframe` | `` `fetch events, from: now()-${timeframe}, to: now()` `` |\n| `src/capabilities/get-events-for-cluster.ts` | 27 | `clusterId`, `kubernetesEntityId` | `` `\\| filter k8s.cluster.uid == \"${clusterId}\" or dt.entity.kubernetes_cluster == \"${kubernetesEntityId}\"` `` |\n\nAll Zod schemas for these parameters use `z.string()` or `z.array(z.string())` with no pattern validation.\n\n### PoC\n**`clusterId` - quote-and-comment break-out.** With `clusterId = 'x\" or 1==1 //'` the constructed query becomes:\n\n```\n| filter k8s.cluster.uid == \"x\" or 1==1 //\" or dt.entity.kubernetes_cluster == \"\"\n```\n\nThe first `\"` closes the string literal, `or 1==1` neutralises the filter to match every row, and `//` discards the rest of the line including the `kubernetesEntityId` guard.\n\n**`entityNames` - pipeline-stage injection.** With `entityNames = ['svc\" | fields id, name, tags //']` the constructed smartscape query becomes:\n\n```\nsmartscapeNodes \"*\" | search \"*svc\" | fields id, name, tags //*\" | fields id, name, type\n```\n\nAfter the `//` line comment, the effective query is `smartscapeNodes \"*\" | search \"*svc\" | fields id, name, tags`. The original `| fields id, name, type` stage is suppressed and replaced with the attacker's field selection - the tool returns whatever field set the attacker requests (including ones not in the tool's documented output contract).\n\n**`timeframe` - prefix injection.** With `timeframe = '30d, to: now() | fieldsAdd internal_secret //'` the list-problems query becomes:\n\n```\nfetch dt.davis.problems, from: now()-30d, to: now() | fieldsAdd internal_secret //, to: now()\n| filter isNull(dt.davis.is_duplicate) OR not(dt.davis.is_duplicate)\n...\n```\n\nA new pipeline stage is injected before the tool's intended `| filter`, and the rest of the query is commented out.\n\nThe server's own `verify_dql` tool can be used to confirm any specific injection payload parses as valid DQL.\n\n### Impact\n- A caller (typically via prompt injection of an LLM that has access to the affected tools) can bypass the tools' field-scope, time-window, and display caps.\n- The affected tools are annotated `readOnlyHint: true`, which some MCP clients treat as a signal to auto-approve. The injection turns a \"safe\" read tool into an arbitrary-DQL surface.\n- No new data access beyond what `execute_dql` already provides - the marginal impact is the auto-approval pathway and the broken tool contract, not privilege escalation.","status":"published","published":"2026-07-31T15:56:12Z","modified":"2026-11-09T21:00:00Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","level":"medium"}],"cwes":["CWE-89","CWE-943"],"updated_at":"2026-11-09T21:19:53.571625Z"}],"nvd":[{"id":"CVE-2026-123810","description":"Dynatrace MCP Server is an MCP server for Dynatrace Observability. Prior to 2.1.1, several read capabilities interpolate caller-controlled values into DQL without sufficient validation or escaping. The src/capabilities/find-monitored-entity-by-name.ts capability embeds entityNames in string searches, src/capabilities/list-problems.ts, src/capabilities/list-vulnerabilities.ts, and src/capabilities/list-exceptions.ts embed timeframe values, and src/capabilities/get-events-for-cluster.ts embeds timeframe, clusterId, and kubernetesEntityId. Crafted values can close string literals, append pipeline stages, or comment out the remaining intended query, allowing callers to bypass field selection, time-window, and result-display limits in tools marked readOnlyHint. The issue does not grant data access beyond the configured token's existing execute_dql capability, but it breaks the narrower auto-approved tool contract. This issue is fixed in version 2.1.1.","status":"published","published":"2026-11-09T22:18:37.133Z","modified":"2026-11-10T17:17:24.123Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-89"],"updated_at":"2026-11-10T20:21:09.433618Z"}],"osv":[{"id":"CVE-2026-123810","title":"Dynatrace MCP Server: DQL injection via parameters not documented as DQL","description":"Dynatrace MCP Server is an MCP server for Dynatrace Observability. Prior to 2.1.1, several read capabilities interpolate caller-controlled values into DQL without sufficient validation or escaping. The src/capabilities/find-monitored-entity-by-name.ts capability embeds entityNames in string searches, src/capabilities/list-problems.ts, src/capabilities/list-vulnerabilities.ts, and src/capabilities/list-exceptions.ts embed timeframe values, and src/capabilities/get-events-for-cluster.ts embeds timeframe, clusterId, and kubernetesEntityId. Crafted values can close string literals, append pipeline stages, or comment out the remaining intended query, allowing callers to bypass field selection, time-window, and result-display limits in tools marked readOnlyHint. The issue does not grant data access beyond the configured token's existing execute_dql capability, but it breaks the narrower auto-approved tool contract. This issue is fixed in version 2.1.1.","status":"published","published":"2026-11-09T20:59:50.956Z","modified":"2026-11-11T02:48:45.196346615Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","level":"medium"}],"cwes":["CWE-89"],"updated_at":"2026-11-11T03:22:00.901153Z"},{"id":"GHSA-pqh8-p93p-2rx7","title":"@dynatrace-oss/dynatrace-mcp-server has a DQL injection via parameters not documented as DQL","description":"### Summary\nA DQL injection vulnerability in several read tools lets a caller bypass the tools' documented field-scope, time-window, and display caps by injecting DQL pipeline stages through parameters typed as identifiers.\n\n### Details\nSeveral tools interpolate caller-supplied parameters directly into DQL query strings without quoting or escaping. The affected parameters are documented in their Zod schemas as identifiers or constrained shorthand (such as `\"24h\"` timeframe values or Kubernetes UIDs) - not as DQL expressions. The interpolation lets a caller break out of string literals, append arbitrary DQL pipeline stages, and use `//` line comments (documented in the [Dynatrace DQL language reference](https://docs.dynatrace.com/docs/discover-dynatrace/platform/grail/dynatrace-query-language/dql-reference)) to discard the rest of the intended query.\n\nThe marginal-privilege ceiling is low because the operator's token also exposes `execute_dql` with full DQL access. What the injection grants is the ability to bypass the affected tools' contract: the `readOnlyHint: true` annotation that MCP clients may treat as a signal to auto-approve, the per-tool field selection (e.g., `| fields id, name, type`), the display caps (`maxProblemsToDisplay`, `maxVulnerabilitiesToDisplay`, `maxEntitiesToDisplay`), and the time-window bounds.\n\nThe vulnerable interpolations are:\n\n| File | Line | Parameter | Interpolation |\n|------|------|-----------|---------------|\n| `src/capabilities/find-monitored-entity-by-name.ts` | 23 | `entityNames[]` | `` `fetch ${entityType} \\| search \"*${entityNames.join('*\" OR \"*')}*\" \\| fieldsAdd entity.type \\| expand tags` `` |\n| `src/capabilities/find-monitored-entity-by-name.ts` | 41 | `entityNames[]` | `` `smartscapeNodes \"*\" \\| search \"*${entityNames.join('*\" OR \"*')}*\" \\| fields id, name, type` `` |\n| `src/capabilities/list-problems.ts` | 27 | `timeframe` | `` `fetch dt.davis.problems, from: now()-${timeframe}, to: now()` `` |\n| `src/capabilities/list-vulnerabilities.ts` | 19 | `timeframe` | `` `fetch security.events, from: now()-${timeframe}, to: now()` `` |\n| `src/capabilities/list-exceptions.ts` | 11 | `timeframe` | `` `fetch user.events, from: now()-${timeframe}, to: now()` `` |\n| `src/capabilities/get-events-for-cluster.ts` | 20 | `timeframe` | `` `fetch events, from: now()-${timeframe}, to: now()` `` |\n| `src/capabilities/get-events-for-cluster.ts` | 27 | `clusterId`, `kubernetesEntityId` | `` `\\| filter k8s.cluster.uid == \"${clusterId}\" or dt.entity.kubernetes_cluster == \"${kubernetesEntityId}\"` `` |\n\nAll Zod schemas for these parameters use `z.string()` or `z.array(z.string())` with no pattern validation.\n\n### PoC\n**`clusterId` - quote-and-comment break-out.** With `clusterId = 'x\" or 1==1 //'` the constructed query becomes:\n\n```\n| filter k8s.cluster.uid == \"x\" or 1==1 //\" or dt.entity.kubernetes_cluster == \"\"\n```\n\nThe first `\"` closes the string literal, `or 1==1` neutralises the filter to match every row, and `//` discards the rest of the line including the `kubernetesEntityId` guard.\n\n**`entityNames` - pipeline-stage injection.** With `entityNames = ['svc\" | fields id, name, tags //']` the constructed smartscape query becomes:\n\n```\nsmartscapeNodes \"*\" | search \"*svc\" | fields id, name, tags //*\" | fields id, name, type\n```\n\nAfter the `//` line comment, the effective query is `smartscapeNodes \"*\" | search \"*svc\" | fields id, name, tags`. The original `| fields id, name, type` stage is suppressed and replaced with the attacker's field selection - the tool returns whatever field set the attacker requests (including ones not in the tool's documented output contract).\n\n**`timeframe` - prefix injection.** With `timeframe = '30d, to: now() | fieldsAdd internal_secret //'` the list-problems query becomes:\n\n```\nfetch dt.davis.problems, from: now()-30d, to: now() | fieldsAdd internal_secret //, to: now()\n| filter isNull(dt.davis.is_duplicate) OR not(dt.davis.is_duplicate)\n...\n```\n\nA new pipeline stage is injected before the tool's intended `| filter`, and the rest of the query is commented out.\n\nThe server's own `verify_dql` tool can be used to confirm any specific injection payload parses as valid DQL.\n\n### Impact\n- A caller (typically via prompt injection of an LLM that has access to the affected tools) can bypass the tools' field-scope, time-window, and display caps.\n- The affected tools are annotated `readOnlyHint: true`, which some MCP clients treat as a signal to auto-approve. The injection turns a \"safe\" read tool into an arbitrary-DQL surface.\n- No new data access beyond what `execute_dql` already provides - the marginal impact is the auto-approval pathway and the broken tool contract, not privilege escalation.","status":"published","published":"2026-07-31T15:56:12Z","modified":"2026-11-09T21:15:04.180184657Z","cvss":[{"version":"3.1","score":4.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N","level":"medium"}],"cwes":["CWE-89","CWE-943"],"updated_at":"2026-11-09T21:40:33.762141Z"}]}}
