NewApp Monitoring is liveSign up free
AgentbeamBeta
AI agent vulnerability · Other MCP servers and tools

GHSA-pqh8-p93p-2rx7: @dynatrace-oss/dynatrace-mcp-server has a DQL injection via parameters not documented as DQL

mediumCVSS 3.1 4.3

Several read-only tools in the Dynatrace MCP server (@dynatrace-oss/dynatrace-mcp-server) put caller-supplied values straight into DQL query strings. A caller, often an LLM steered by prompt injection, can inject pipeline stages and bypass each tool's field list, time window and display caps. The extra access is low. Fixed in 2.1.1.

Published Jul 31, 2026 · Analysis Oct 25, 2026

What an attacker can do

Tools such as find-monitored-entity-by-name, list-problems, list-vulnerabilities, list-exceptions and get-events-for-cluster build DQL by string interpolation. The entityNames, timeframe, clusterId and kubernetesEntityId parameters are plain z.string() values with no pattern check. A quote closes the DQL string, extra stages follow, and a // comment discards the rest of the intended query.

Examples from the report: clusterId set to x" or 1==1 // turns the Kubernetes filter into one that matches every row. A timeframe of 30d, to: now() | fieldsAdd internal_secret // adds a stage before the tool's own filter. An entityNames entry ending in | fields id, name, tags // replaces the tool's fixed field selection.

The ceiling is low because the same token already exposes execute_dql with full DQL access. What breaks is the tool contract. These tools carry readOnlyHint: true, which some MCP clients treat as a reason to auto-approve, so injection through them can run attacker-shaped queries without a prompt. The advisory says there is no new data access beyond what execute_dql gives.

Who is affected

@dynatrace-oss/dynatrace-mcp-server before 2.1.1. Any deployment where an LLM or client can call the affected read tools with untrusted input is in scope; the risk is highest where the client auto-approves tools marked read-only.

npm ls @dynatrace-oss/dynatrace-mcp-server
npm ls -g @dynatrace-oss/dynatrace-mcp-server

@dynatrace-oss/dynatrace-mcp-server

Ecosystem
npm
Affected
< 2.1.1
Fixed in
2.1.1
Check
npm ls @dynatrace-oss/dynatrace-mcp-server

How to fix it

Upgrade to 2.1.1:

npm install @dynatrace-oss/[email protected]

The release lists one security change, validate and escape DQL template parameters (PR 562). The notes do not describe how the validation works. The advisory names no workaround. Until you upgrade, do not auto-approve these tools on the strength of readOnlyHint alone, and keep the token scoped to the data the agent needs.

How to tell if you were hit

Look in MCP client logs and Dynatrace query history for calls to the listed tools whose arguments hold a double quote, a // sequence, a pipe, or words like fieldsAdd and fields inside entityNames, timeframe, clusterId or kubernetesEntityId. A timeframe should look like 24h or 7d. Cluster ids should be plain UIDs. Queries that return fields outside a tool's documented output are another sign. Beam records agent MCP tool calls, so those arguments can be reviewed there.

Original advisory

From the GitHub Advisory Database (CC BY 4.0).

Summary

A 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.

Details

Several 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) to discard the rest of the intended query.

The 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.

The vulnerable interpolations are:

| File | Line | Parameter | Interpolation |
| `src/capabilities/find-monitored-entity-by-name.ts` | 23 | `entityNames[]` | `` `fetch ${entityType} \| search "*${entityNames.join('*" OR "*')}*" \| fieldsAdd entity.type \| expand tags` `` |
| `src/capabilities/find-monitored-entity-by-name.ts` | 41 | `entityNames[]` | `` `smartscapeNodes "*" \| search "*${entityNames.join('*" OR "*')}*" \| fields id, name, type` `` |
| `src/capabilities/list-problems.ts` | 27 | `timeframe` | `` `fetch dt.davis.problems, from: now()-${timeframe}, to: now()` `` |
| `src/capabilities/list-vulnerabilities.ts` | 19 | `timeframe` | `` `fetch security.events, from: now()-${timeframe}, to: now()` `` |
| `src/capabilities/list-exceptions.ts` | 11 | `timeframe` | `` `fetch user.events, from: now()-${timeframe}, to: now()` `` |
| `src/capabilities/get-events-for-cluster.ts` | 20 | `timeframe` | `` `fetch events, from: now()-${timeframe}, to: now()` `` |
| `src/capabilities/get-events-for-cluster.ts` | 27 | `clusterId`, `kubernetesEntityId` | `` `\| filter k8s.cluster.uid == "${clusterId}" or dt.entity.kubernetes_cluster == "${kubernetesEntityId}"` `` |

All Zod schemas for these parameters use z.string() or z.array(z.string()) with no pattern validation.

PoC

`clusterId` - quote-and-comment break-out. With clusterId = 'x" or 1==1 //' the constructed query becomes:

| filter k8s.cluster.uid == "x" or 1==1 //" or dt.entity.kubernetes_cluster == ""

The 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.

`entityNames` - pipeline-stage injection. With entityNames = ['svc" | fields id, name, tags //'] the constructed smartscape query becomes:

smartscapeNodes "*" | search "*svc" | fields id, name, tags //*" | fields id, name, type

After 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).

`timeframe` - prefix injection. With timeframe = '30d, to: now() | fieldsAdd internal_secret //' the list-problems query becomes:

fetch dt.davis.problems, from: now()-30d, to: now() | fieldsAdd internal_secret //, to: now()
| filter isNull(dt.davis.is_duplicate) OR not(dt.davis.is_duplicate)
...

A new pipeline stage is injected before the tool's intended | filter, and the rest of the query is commented out.

The server's own verify_dql tool can be used to confirm any specific injection payload parses as valid DQL.

Impact

  • 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.
  • 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.
  • 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.

Credited to yotampe-pluto.

Questions

Is this worse than the access execute_dql already gives?

No. The advisory states the marginal privilege is low because the token already allows execute_dql. The real risk is that read tools marked readOnlyHint true may be auto-approved and then run injected DQL.

What input triggers the injection?

Values in entityNames, timeframe, clusterId and kubernetesEntityId. They are interpolated into DQL, so a quote plus a // comment can break out of the intended query.

Which version fixes GHSA-pqh8-p93p-2rx7?

2.1.1, which validates and escapes DQL template parameters. Every earlier version is listed as vulnerable.

References

How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology

More Other MCP servers and tools vulnerabilities

All Other MCP servers and tools entries