Skip to content

fix: block dangerous Elasticsearch query types in MCP searchWithDirectQuery#27730

Open
JasonOA888 wants to merge 2 commits intoopen-metadata:mainfrom
JasonOA888:fix/block-dangerous-es-query-types
Open

fix: block dangerous Elasticsearch query types in MCP searchWithDirectQuery#27730
JasonOA888 wants to merge 2 commits intoopen-metadata:mainfrom
JasonOA888:fix/block-dangerous-es-query-types

Conversation

@JasonOA888
Copy link
Copy Markdown

@JasonOA888 JasonOA888 commented Apr 25, 2026

Summary

The MCP searchMetadata tool accepts a user-controlled queryFilter that is parsed as raw JSON and passed directly to Elasticsearch via Query.of(q -> q.withJson(...)). While RBAC conditions are applied as filters afterward, the user query itself is not validated for dangerous query types.

This means an authenticated MCP user could craft queries using:

  • script — execute arbitrary Painless/Groovy scripts server-side
  • script_score — script-based scoring with arbitrary code
  • wrapper — base64-encoded queries that can hide nested dangerous types
  • percolator — reverse query matching
  • scripted_metric — script-based aggregation with init/map/combine/reduce scripts

Fix

Add validateQuerySafety() which recursively walks the parsed JSON query tree and rejects any node containing a blocked query type key:

static final Set<String> BLOCKED_QUERY_TYPES =
    Set.of("script", "script_score", "percolator", "wrapper", "scripted_metric");

static void validateQuerySafety(JsonNode node) throws IOException {
    if (node == null || !node.isObject()) return;
    for (String blockedType : BLOCKED_QUERY_TYPES) {
        if (node.has(blockedType)) {
            throw new IOException("queryFilter contains blocked query type

----
## Summary by Gitar

- **Security enhancements:**
  - Added `function_score` and `runtime_mappings` to `BLOCKED_QUERY_TYPES` in `SearchMetadataTool` to prevent potential injection vulnerabilities.
- **Testing:**
  - Added unit tests in `SearchMetadataToolTest` to verify that `function_score` and `runtime_mappings` are correctly rejected.

<sub>This will update automatically on new commits.</sub>

…tQuery

The MCP searchMetadata tool accepts a user-controlled queryFilter that
is passed directly to Elasticsearch via Query.of(q -> q.withJson(...)).
Without validation, an authenticated MCP user could craft queries using
script, script_score, wrapper, percolator, or scripted_metric types —
enabling arbitrary code execution (painless/groovy), query obfuscation
(wrapper base64), or denial-of-service.

Add validateQuerySafety() which recursively walks the parsed JSON query
tree and rejects any node containing a blocked query type key. This
check runs before the query reaches Elasticsearch, ensuring dangerous
types are blocked regardless of nesting depth (e.g., inside bool clauses).

Signed-off-by: Jason L <jason@outland.art>
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment thread openmetadata-mcp/src/main/java/org/openmetadata/mcp/tools/SearchMetadataTool.java Outdated
Address review feedback:
- Add function_score (allows script injection via scoring functions)
- Add runtime_mappings (allows Painless scripts at query time)
- Fix duplicate import java.util.Map
- Add tests for both new blocked types

Reported-by: gitar-bot[bot]
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@gitar-bot
Copy link
Copy Markdown

gitar-bot Bot commented Apr 25, 2026

Code Review ✅ Approved 2 resolved / 2 findings

Restricts function_score and runtime_mappings in MCP search queries to prevent security risks. Removes duplicate imports to resolve compilation errors.

✅ 2 resolved
Security: Blocklist missing function_score and runtime_mappings

📄 openmetadata-mcp/src/main/java/org/openmetadata/mcp/tools/SearchMetadataTool.java:472-478
The BLOCKED_QUERY_TYPES set blocks script, script_score, wrapper, percolator, and scripted_metric, but misses at least two other Elasticsearch features that allow arbitrary Painless script execution:

  1. function_score — supports script_score as a scoring function inside its functions array. While the recursive validator might catch a nested script_score key, function_score also supports script fields directly in field_value_factor alternatives, and blocking the entry-point query type is the safer approach.
  2. runtime_mappings — allows defining runtime fields with inline Painless scripts at query time, enabling arbitrary code execution. This is typically a top-level key rather than nested inside query, so if a user passes it at the root of queryFilter, it would not be caught.

Since this PR is specifically a security hardening fix, missing these vectors undermines the purpose of the change.

Quality: Duplicate import java.util.Map will cause compile error

📄 openmetadata-mcp/src/main/java/org/openmetadata/mcp/tools/SearchMetadataTool.java:16 📄 openmetadata-mcp/src/main/java/org/openmetadata/mcp/tools/SearchMetadataTool.java:18
Line 16 and line 18 both import java.util.Map. Most Java compilers treat duplicate imports as a compilation error or at minimum a warning that will fail strict CI checks.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant