[ ⌘K ]
← BACK TO SEARCH

chewcw/adx-mcp-server

critical

No description

MCP server (purpose undetermined)

purpose: MCP server (purpose undetermined)threat: network exposed
TypeScript0May 20, 2026May 20, 2026GITHUB
5/20/2026
high1 finding
src/adxMcpServer.ts
119  private registerConfigResource() {
120    this.server.resource(
121      "config",
122      "config://azure-data-explorer-creds",
123      async (_: { href: string }) => {
124        return {
125          contents: [
126            {
127              uri: "config://azure-data-explorer-creds/cluster-name",
128              name: "Cluster Name",
129              text: `${process.env.ADX_CLUSTER_NAME}`,
130            },
131            {
132              uri: "config://azure-data-explorer-creds/client-id",
133              name: "Client ID",
134              text: `${process.env.ADX_CLIENT_ID}`,
135            },
136            {
137              uri: "config://azure-data-explorer-creds/client-secret",
138              name: "Client Secret",
139              text: `${process.env.ADX_CLIENT_SECRET ? "******" : "Not set"}`,
140            },
141            {
142              uri: "config://azure-data-explorer-creds/tenant-id",
143              name: "Tenant ID",
144              text: `${process.env.ADX_TENANT_ID}`,
145            },
146          ],
147        }
148      }
149    )
150  }
src/index.ts:1src/adxMcpServer.ts:1-7

// Exploitable if MCP is exposed to untrusted prompts or if a compromised LLM can read resources.

The config resource exposes environment variables ADX_CLUSTER_NAME, ADX_CLIENT_ID, and ADX_TENANT_ID in plaintext. While the client secret is masked, the other credentials are leaked. This resource is accessible to any client that can read resources from the MCP server.

ImpactAn attacker with access to the MCP server can retrieve the cluster name, client ID, and tenant ID, which are sensitive credentials for Azure Data Explorer. This could facilitate further attacks on the Azure resource.

FixRemove the config resource or mask all sensitive fields. Consider using a secure credential store and never expose credentials via MCP resources.

high1 finding
src/adxMcpServer2.ts
55    this.server.setRequestHandler(ReadResourceRequestSchema, async (request: z.infer<typeof ReadResourceRequestSchema>) => {
56      const uri = request.params.uri
57
58      if (uri.startsWith("config://azure-data-explorer-creds")) {
59        return {
60          contents: [
61            {
62              uri: "config://azure-data-explorer-creds/cluster-name",
63              name: "Cluster Name",
64              text: `${process.env.ADX_CLUSTER_NAME}`,
65            },
66            {
67              uri: "config://azure-data-explorer-creds/client-id",
68              name: "Client ID",
69              text: `${process.env.ADX_CLIENT_ID}`,
70            },
71            {
72              uri: "config://azure-data-explorer-creds/client-secret",
73              name: "Client Secret",
74              text: `${process.env.ADX_CLIENT_SECRET ? "******" : "Not set"}`,
75            },
76            {
77              uri: "config://azure-data-explorer-creds/tenant-id",
78              name: "Tenant ID",
79              text: `${process.env.ADX_TENANT_ID}`,
80            },
81          ],
82        }
83      }
84    })
src/index.ts:1src/adxMcpServer2.ts:1-12

// Exploitable if MCP is exposed to untrusted prompts or if a compromised LLM can read resources.

Same as above, but in the alternative server implementation. The config resource exposes ADX_CLUSTER_NAME, ADX_CLIENT_ID, and ADX_TENANT_ID in plaintext.

ImpactAn attacker can retrieve sensitive Azure credentials, enabling further attacks on the Azure Data Explorer instance.

FixRemove the config resource or mask all sensitive fields. Use a secure credential store.

high1 finding
src/adxMcpServer.ts
152  private registerQueryTool() {
153    this.server.tool(
154      "query",
155      { query: z.string(), db: z.string() },
156      async (data: z.infer<typeof this.QueryToolSchema>) => {
157        if (!this.client) {
158          throw new Error("Client is not initialized")
159        }
160        const query = data.query
161        const db = data.db
162        const response = await this.client.execute(String(db), String(query))
163        const result = response.primaryResults[0].toString()
164        return {
165          content: [{
166            type: "text",
167            text: result,
168          }],
169        }
170      }
171    )
172  }
src/index.ts:1src/adxMcpServer.ts:1-7

// Exploitable if MCP is exposed to untrusted prompts or if a compromised LLM can call tools.

The query tool accepts arbitrary Kusto Query Language (KQL) queries from the user without any validation or sanitization. The 'db' parameter is also user-controlled and used directly in the execute call. This allows an attacker to run any KQL query, including administrative commands like '.show operations' or '.drop tables'.

ImpactAn attacker could execute arbitrary KQL queries, potentially reading, modifying, or deleting data in the Azure Data Explorer database. This could lead to data exfiltration, data loss, or privilege escalation.

FixImplement strict input validation: restrict allowed queries to a whitelist of safe operations, or use parameterized queries if supported. Validate the 'db' parameter against a list of allowed databases.

medium1 finding
src/adxMcpServer.ts
40  private registerSchemaResourceTemplate() {
41    this.server.resource(
42      "Schema of the db",
43      new ResourceTemplate("schema://adx/{db}", { list: undefined }),
44      async (uri: URL, variables: Variables, _extra: RequestHandlerExtra) => {
45        if (!this.client) {
46          throw new Error("Client is not initialized")
47        }
48        
49        const query = `.show tables`
50        const response = await this.client.execute(String(variables.db), query)
51        const result = response.primaryResults[0].toString()
52        ...
53      },
54    )
55
56    this.server.resource(
57      "Schema of the table",
58      new ResourceTemplate("schema://adx/{db}/{table}", { list: undefined }),
59      async (uri: URL, variables: Variables, _extra: RequestHandlerExtra) => {
60        ...
61        const query = `${variables.table} | getschema`
62        const response = await this.client.execute(String(variables.db), query)
63        ...
64      },
65    )
66
67    this.server.resource(
68      "Functions of the db",
69      new ResourceTemplate("functions://adx/{db}/functions", { list: undefined }),
70      async (uri: URL, variables: Variables, extra: RequestHandlerExtra) => {
71        ...
72        const query = `.show functions`
73        const response = await this.client.execute(String(variables.db), query)
74        ...
75      },
76    )
77  }
src/index.ts:1src/adxMcpServer.ts:1-7

// Exploitable if MCP is exposed to untrusted prompts or if a compromised LLM can read resources.

The resource templates accept user-controlled 'db' and 'table' parameters from the URI. These are used directly in KQL queries without validation. While the queries are hardcoded (except for the table name in the second template), the 'db' parameter is used to select the database context, and an attacker could potentially access databases they should not have access to. The table name is directly interpolated into the query, which could allow injection if the table name contains special characters.

ImpactAn attacker could potentially access or enumerate databases and tables beyond the intended scope. The table name injection could allow arbitrary KQL execution if the table name is crafted maliciously.

FixValidate the 'db' parameter against a whitelist of allowed databases. Sanitize or parameterize the 'table' parameter to prevent injection.

medium1 finding
src/adxMcpServer2.ts
110    this.server.setRequestHandler(ReadResourceRequestSchema, async (request: z.infer<typeof ReadResourceRequestSchema>) => {
111      const uri = request.params.uri
112      const showTablesRegex = /schema:\/\/adx\/\w+$/
113      if (showTablesRegex.test(uri)) {
114        const db = uri.split("/")[3]
115        ...
116        const query = `.show tables`
117        const response = await this.client.execute(db, query)
118        ...
119      }
120      const showTableSchemaRegex = /schema:\/\/adx\/\w+\/\w+$/
121      if (showTableSchemaRegex.test(uri)) {
122        const db = uri.split("/")[3]
123        const table = uri.split("/")[4]
124        ...
125        const query = `${table} | getschema`
126        const response = await this.client.execute(db, query)
127        ...
128      }
129      const showFunctionsRegex = /schema:\/\/adx\/\w+\/functions$/
130      if (showFunctionsRegex.test(uri)) {
131        const db = uri.split("/")[3]
132        ...
133        const query = `.show functions`
134        const response = await this.client.execute(db, query)
135        ...
136      }
137    })
src/index.ts:1src/adxMcpServer2.ts:1-12

// Exploitable if MCP is exposed to untrusted prompts or if a compromised LLM can read resources.

Same as above, but in the alternative implementation. The regex patterns only allow alphanumeric characters (\w+), which reduces injection risk but still does not validate the database name against a whitelist. The table name is directly interpolated into the query.

ImpactAn attacker could potentially access databases beyond the intended scope. The table name injection is limited by the regex but still possible if the regex is bypassed (e.g., using Unicode).

FixValidate the 'db' parameter against a whitelist of allowed databases. Use parameterized queries for the table name.

env.exposure
100
LLM-based
high findings+75
medium findings+30