Skip to content

Parse-gap bypasses in mcp-context-forge: SQL Sanitizer (privesc/DROP/mass-DELETE) and resource_filter SSRF

High
brian-hussey published GHSA-9qxh-fpx5-vxvw Aug 25, 2026

Package

pip package mcp-contextforge-gateway (pip)

Affected versions

< v1.0.7

Patched versions

v1.0.7

Description

Summary

Two shipping policy plugins — sql_sanitizer and resource_filter — decide over a string
(flat regex / urlparse().netloc) while the downstream consumer parses the same string with a
real grammar (a SQL engine; an RFC-3986/WHATWG URL parser). The two parses disagree, so a plugin
allows an argument the downstream then executes as the exact forbidden operation the plugin exists
to block (a monitor-vs-executor parse gap). Impact: the SQL sanitizer can be bypassed to run
privilege-escalating UPDATE, DROP TABLE, and unscoped mass DELETE; the resource filter can be
bypassed for SSRF to a blocked domain. Confirmed on main @ 7b17f124bec1c46a94ab0d619c9727493236dffa
(2026-07-16).

Details

SQL Sanitizerplugins/sql_sanitizer/sql_sanitizer.py. There is no real SQL parser (import re
only, line ~21). _find_issues() (line ~138) strips comments with
_BLOCK_COMMENT_RE = re.compile(r"/\*.*?\*/", re.DOTALL) (line ~55, applied line ~119),
keyword-blocklists DROP/TRUNCATE/… via regex, and flags DELETE/UPDATE "without WHERE" via
_WHERE_RE = re.compile(r"\bWHERE\b", re.IGNORECASE) (line ~58; checks at lines ~158 and ~162).
Because these are flat-text operations over the raw query string, several parse divergences with a real
SQL engine slip past the checks (see PoC).

resource_filterplugins/resource_filter/resource_filter.py. The domain filter computes
parsed = urlparse(payload.uri) then domain_lower = parsed.netloc.lower() (line ~112) and blocks by
equality / endswith("." + d) (line ~114). netloc includes any userinfo@, so it differs from
the host a URL library actually connects to (urlparse(uri).hostname), enabling SSRF (see PoC).

PoC

SQL Sanitizer (shipping defaults block_update_without_where, block_delete_without_where,
strip_comments). Each returns no issue (allow); a SQL engine executes the destructive operation
(verified with the real _find_issues and stdlib sqlite3):

  1. Privilege escalationWHERE inside a string literal satisfies the "UPDATE without WHERE" check:
    UPDATE users SET is_admin=1, note='flagged WHERE approved'
  2. DDL bypassDROP hidden between string literals is removed by the DOTALL comment stripper
    before the blocklist runs:
    SELECT '/*' AS x; DROP TABLE users; SELECT '*/' AS y
  3. Unscoped DELETE — statement-scope confusion (the WHERE belongs to the trailing SELECT):
    DELETE FROM users; SELECT 1 WHERE 1=1

resource_filter (blocked_domains=["evil.com"]):
http://good.com@evil.com/xnetloc = "good.com@evil.com", which neither equals evil.com nor ends
with .evil.comnot blocked. The true host — per Python urlparse(...).hostname and Node
new URL(...).hostname — is evil.com → SSRF past the filter.

(Engine-specific variant to review: MySQL/MariaDB executable comments /*! … */, executed by the
engine but treated as a comment by the stripper/parser; not tested against a live MySQL.)

Impact

The SQL sanitizer is deployed to stop dangerous SQL reaching a database MCP server → the bypasses yield
full-table privilege escalation, table drops, and mass deletion (integrity/confidentiality/availability
of the DB). The resource filter is deployed to block egress to disallowed hosts → the bypass yields
SSRF to a blocked domain. Any deployment relying on these plugins as a security control is affected.
Root cause is a monitor-vs-executor interpretation conflict: the plugin's string/regex view diverges
from the executor's grammar. Remediation: decide over a real parse — sqlglot typed statements for
SQL (per-statement kind + a genuine WHERE node, not a keyword inside a literal), and
urlparse(uri).hostname (+ IDN/alt-IP normalization) for URLs — binding the policy to the same
canonical parse the downstream uses. Reproduction scripts available; we propose a 90-day coordinated-
disclosure embargo (part of an academic study).

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

CVE ID

No known CVE

Weaknesses

Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data. Learn more on MITRE.

Interpretation Conflict

Product A handles inputs or steps differently than Product B, which causes A to perform incorrect actions based on its perception of B's state. Learn more on MITRE.

Server-Side Request Forgery (SSRF)

The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination. Learn more on MITRE.

Credits