CVE-2026-97228
Executive Summary
CVE-2026-97228 is a GraphQL query injection vulnerability in Rapid7's Bulk Export MCP server (versions 0.2.5 through 0.6.1). The flaw exists in the get_export_status function within src/export_manager.py, where an unvalidated export_id argument is concatenated directly into a GraphQL query string instead of being passed as a parameterized variable. An attacker capable of supplying a malicious export_id — via the check_rapid7_export_status or download_rapid7_export MCP tools, and typically through a compromised or careless upstream MCP client or indirect prompt injection — can terminate the intended query and append arbitrary GraphQL selections, potentially including schema introspection. The impact is limited to the operator's own authenticated API scope and cannot cross tenant boundaries.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The vulnerability resides in the Rapid7 Bulk Export MCP (Model Context Protocol) server, a companion tool that exposes Rapid7 export functionality to MCP-compatible clients such as AI assistants or automation agents. Versions 0.2.5 through 0.6.1 contain a query-construction defect in src/export_manager.py, specifically inside the get_export_status function.
The function builds a GraphQL document for the Rapid7 export API. The intended selection resembles export(id: "<export_id>"), where <export_id> is the value supplied by the caller. Rather than binding that value as a GraphQL variable, the implementation interpolates it verbatim into the query string. Because this value arrives as an unvalidated MCP tool argument — passed through the check_rapid7_export_status and download_rapid7_export tools — an attacker who controls the argument can inject GraphQL structural characters.
GraphQL syntax uses double quotes to delimit string literals and braces to delimit selection sets. If an attacker supplies an export_id containing a quote and brace sequence, the string literal can be closed prematurely and the intended export(id: "...") selection terminated. The attacker can then append additional root-level selections. Because GraphQL allows multiple root fields in a single document, the injected content is merged into one well-formed GraphQL request. The resulting document is sent to the Rapid7 export API using the operator's own API key.
This is a classic CWE-943 (Improper Neutralization of Special Elements in Data Query Logic) issue, a GraphQL-specific analogue of SQL injection. The injection does not create new privileges. Every query executes within the operator's already-authenticated API scope, under the operator's valid API key, and cannot traverse tenant or account boundaries. Consequently, the confidentiality impact is low (C:L), and integrity and availability impacts are none (I:N/A:N). The CVSS vector reflects high privileges required (PR:H), because exploitation presupposes the ability to influence MCP tool arguments.
The practical exposure path is indirect: a compromised or careless upstream MCP client, or an indirect prompt injection that forwards an attacker-supplied identifier into the tool argument. A directly malicious operator gains nothing beyond what direct API access already provides.
The root cause is the absence of parameterization. The fix in version 0.6.2 passes export_id as a GraphQL variable declared as $exportId: ID!, which decouples the data value from the query structure and eliminates the injection primitive.
Exploitation Scenarios
No public proof-of-concept, exploit code, or Nuclei template is available. The attack chain below is inferred from the vulnerability class and the details provided in the NVD description.
Reconnaissance / target identification. The attacker identifies a deployment running Rapid7 Bulk Export MCP versions 0.2.5 through 0.6.1 and an MCP client that invokes the
check_rapid7_export_statusordownload_rapid7_exporttools with caller-influenced arguments. The attacker does not need network access to the Rapid7 API directly; the presence of the MCP client and its tool-calling interface is the attack surface.Triggering the flaw class. The attacker supplies a crafted
export_idvalue. Because the value is an unvalidated MCP tool argument reachingget_export_statusinsrc/export_manager.py, and because the function interpolates it directly into the GraphQL query string, a value containing quote and brace characters can close the intendedexport(id: "...")selection early.Payload / execution method. The attacker appends attacker-controlled root-level selections after the terminated selection, for example schema introspection fields. The result is a single well-formed GraphQL document. The MCP server transmits this document to the Rapid7 export API under the operator's own API key, so the injected selections execute server-side against the Rapid7 API.
Post-exploitation impact. The attacker can retrieve schema information and any fields accessible to the operator's own API scope. No tenant or account boundary can be crossed, and no privilege escalation occurs. The realistic harm is information disclosure within the operator's authorized scope, which the operator could already achieve by calling the API directly. The meaningful risk arises only when the malicious argument is injected by a third party through a compromised MCP client or indirect prompt injection, in which case the third party obtains visibility into the operator's API scope.
Because no public exploit exists, defenders should treat this as a theoretical, low-severity issue and focus on upgrading to version 0.6.2.
Impact Assessment
The CVSS 3.1 base score is 2.7 (Low), with vector CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N. The subscores indicate:
- Attack Vector (N): exploitable over a network path, since MCP tool arguments may be delivered remotely through an MCP client.
- Attack Complexity (L): no special conditions beyond controlling the argument.
- Privileges Required (H): the attacker must already be able to influence MCP tool arguments, i.e., a privileged position.
- User Interaction (N): no separate user action is required once the argument is controlled.
- Scope (U): the impact stays within the operator's own security scope.
- Confidentiality (L): limited information disclosure, bounded by the operator's API scope.
- Integrity (N) and Availability (N): no modification or denial of service.
Business impact is limited. Affected systems are deployments of Rapid7 Bulk Export MCP versions 0.2.5 through 0.6.1. Blast radius is confined to a single tenant/account, because injected queries execute under the operator's own valid API key and cannot cross boundaries. The most credible organizational risk is indirect: an AI assistant or automation agent using the MCP server may forward untrusted input into export_id, causing unintended schema queries against the operator's Rapid7 data. There is no evidence of exploitation in the wild, and CISA KEV does not list this CVE. EPSS has not yet been scored by FIRST.org.
Detection Guidance
Sigma Rule
title: Rapid7 Bulk Export MCP GraphQL Injection Attempt via export_id
id: 9f2c7b41-8a6d-4e3f-9c21-5d7e1a2b3c4d
status: experimental
description: Detects crafted export_id arguments containing quote and brace characters targeting Rapid7 Bulk Export MCP get_export_status.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-97228
author: valtersit.com
date: 2026-01-01
logsource:
category: application
product: rapid7_bulk_export_mcp
detection:
selection_tool:
tool_name:
- 'check_rapid7_export_status'
- 'download_rapid7_export'
selection_payload:
export_id|contains:
- '"}'
- '"){'
- '__schema'
- '__type'
condition: selection_tool and selection_payload
falsepositives:
- Legitimate export identifiers that coincidentally contain quote/brace characters (unlikely)
level: medium
tags:
- attack.t1190
- cve.2026.97228
YARA Rule
rule CVE_2026_97228_Rapid7_MCP_GraphQL_Injection
{
meta:
description = "Detects GraphQL injection payloads in export_id arguments targeting Rapid7 Bulk Export MCP"
author = "valtersit.com"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-97228"
date = "2026-01-01"
severity = "medium"
strings:
$tool1 = "check_rapid7_export_status" ascii wide
$tool2 = "download_rapid7_export" ascii wide
$func = "get_export_status" ascii wide
$inj1 = "__schema" ascii wide
$inj2 = "__type" ascii wide
$close = "\")" ascii
$brace = "\"}" ascii
condition:
(any of ($tool*) or $func) and
(any of ($inj*) or all of ($close, $brace))
}
Suricata IDS Rule
alert http any any -> any any (msg:"CVE-2026-97228 Rapid7 Bulk Export MCP GraphQL Injection Attempt"; flow:established,to_server; http.method; content:"POST"; http.request_body; content:"export"; nocase; http.request_body; content:"__schema"; nocase; http.request_body; content:"__type"; nocase; classtype:attempted-recon; reference:cve,2026-97228; sid:202697228; rev:1;)
Elastic Detection
process where event.action == "network" and
process.name : "python*" and
network.direction == "egress" and
network.protocol == "http" and
(
stringContains(network.request_body, "__schema") or
stringContains(network.request_body, "__type")
) and
stringContains(network.request_body, "export")
Splunk SPL Query
index=main sourcetype=rapid7_mcp:logs OR sourcetype=app:rapid7_mcp
| search (tool_name="check_rapid7_export_status" OR tool_name="download_rapid7_export" OR "get_export_status")
| search (export_id="*\"*" OR export_id="*{*" OR export_id="*__schema*" OR export_id="*__type*")
| stats count min(_time) as first_seen max(_time) as last_seen by host, tool_name, export_id, user
| sort - count
Wazuh OSSEC Rule
<group name="rapid7_mcp,graphql_injection,">
<rule id="202697228" level="8">
<decoded_as>json</decoded_as>
<field name="tool_name">check_rapid7_export_status|download_rapid7_export</field>
<regex field="export_id">.*(__schema|__type|\"\{|\"\}).*</regex>
<description>CVE-2026-97228: Possible GraphQL injection via export_id in Rapid7 Bulk Export MCP</description>
<mitre>
<id>T1190</id>
</mitre>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). Note: the NVD description states the issue is fixed in version 0.6.2 via parameterized GraphQL variables; however, no patch/runtime evidence has been confirmed by the tracked patch sources for this report.
- Immediate mitigations:
- Restrict which MCP clients or users can invoke
check_rapid7_export_statusanddownload_rapid7_export, since exploitation requires the ability to control theexport_idargument (PR:H). - Validate/sanitize
export_idat any proxy or wrapper layer, rejecting values containing quote, brace, or__schema/__typesubstrings before they reach the MCP server. - Treat MCP tool arguments originating from untrusted AI/agent input as untrusted; apply content filtering against indirect prompt injection that forwards identifiers into tool arguments.
- Monitor the application logs using the Sigma, Elastic EQL, Splunk, and Wazuh detections above for injected identifiers.
- Patch / upgrade steps:
- Upgrade Rapid7 Bulk Export MCP to version 0.6.2, which passes
export_idas a parameterized GraphQL variable ($exportId: ID!), eliminating the interpolation primitive. - Verify the upgraded
src/export_manager.pyuses variable binding rather than string interpolation inget_export_status.
- Long-term hardening:
- Enforce parameterized query construction or a GraphQL client library that binds variables for all API interactions.
- Reduce the operator's API key scope to the minimum required, limiting the fields exposed even if injection occurs.
- Apply least privilege to MCP clients and log all tool invocations with argument values for auditability.
- Include MCP servers in the software inventory and subscribe to upstream advisories.
References
- NVD — CVE-2026-97228: https://nvd.nist.gov/vuln/detail/CVE-2026-97228
- MITRE CWE-943 — Improper Neutralization of Special Elements in Data Query Logic: https://cwe.mitre.org/data/definitions/943.html
- FIRST EPSS (not yet scored at time of writing): https://www.first.org/epss/
- CISA Known Exploited Vulnerabilities Catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
- Model Context Protocol specification: https://modelcontextprotocol.io/
No public proof-of-concept, exploit code, or Nuclei template is available. No threat actor campaigns or exploitation-in-the-wild evidence have been reported; CISA KEV does not list CVE-2026-97228. Default CVSS score: 2.7 (Low).
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.