Back to skill

Security audit

subgraph-registry-mcp

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate subgraph discovery MCP server, but its optional HTTP mode can expose unauthenticated endpoints that use the operator's Graph API key.

Install only if you need a subgraph discovery/query MCP server. Keep the default stdio or loopback-only HTTP mode for local use. Do not expose --http or --http-only on a public or shared network with THE_GRAPH_STUDIO_API_KEY, GRAPH_STUDIO_API_KEY, or GATEWAY_API_KEY set unless you add authentication in front of it. Use pinned versions and audit dependencies before production deployment.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
src/index.js:2492
Finding
Unauthenticated Remote MCP Clients Can Consume the Operator's Graph API Quota<![CDATA[ ## Vulnerability Details **File Location**: `src/index.js:2431-2478`, `src/index.js:2492-2515`, and `src/index.js:2654-2670` **Vulnerability Type**: Missing authentication and authorization on credential-bearing MCP endpoints **Risk Level**: Medium ### Vulnerable Code ```js const HANDLERS = { search_subgraphs: searchSubgraphs, recommend_subgraph: recommendSubgraph, get_subgraph_detail: getSubgraphDetail, list_registry_stats: listRegistryStats, semantic_search_subgraphs: semanticSearchSubgraphs, get_schema_changes: getSchemaChanges, execute_query: executeQuery, execute_query_by_subgraph_id: executeQuery, execute_query_by_deployment_id: executeQuery, execute_query_by_ipfs_hash: executeQuery, get_schema: getSchema, get_schema_by_subgraph_id: getSchema, get_schema_by_deployment_id: getSchema, get_schema_by_ipfs_hash: getSchema, get_top_subgraph_deployments: getTopSubgraphDeployments, get_deployment_30day_query_counts: getDeployment30dayQueryCounts, }; function createServer() { const server = new Server( { name: "subgraph-registry", version: PKG_VERSION }, { capabilities: { tools: {} } } ); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: listableTools(), })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const handler = HANDLERS[name]; if (!handler) { return { content: [{ type: "text", text: JSON.stringify({ error: `Unknown tool: ${name}` }) }], isError: true, }; } try { const result = await handler(args || {}); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } catch (err) { return { content: [{ type: "text", text: JSON.stringify({ error: err.message }) }], isError: true, }; } }); return server; } ``` ```js function startHttpTransport(port) { const app = e ...[truncated 4560 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Require authentication on both MCP endpoints** - Authenticate requests to `/sse` before creating a session. - Authenticate every request to `/messages`; do not rely only on possession of a session ID. - Use a securely generated service token, mTLS, or an authenticated reverse proxy. - Compare bearer tokens using a timing-safe comparison. 2. **Add authorization at tool dispatch** - Assign permissions to each authenticated principal. - Explicitly restrict `execute_query*` and live `get_schema*` operations. - Do not treat omission from `tools/list` as an authorization boundary. - Reject direct calls to tools that the current principal is not permitted to use. 3. **Fail safely for keyed non-loopback deployments** - Refuse startup when a Studio API key is configured and the HTTP server binds to a non-loopback interface unless an explicit authentication configuration is present. - Replace the current warning-only behavior with a fatal configuration error. - If an override is necessary, require an explicit option such as `ALLOW_UNAUTHENTICATED_KEYED_HTTP=1` and prominently document its consequences. 4. **Separate public discovery from credentialed execution** - Run the public discovery service without a Studio API key. - Place credentialed execution in a separate loopback-only or private-network process. - Avoid sharing the same unauthenticated transport and handler registry between public discovery and credential-bearing operations. 5. **Implement abuse controls** - Add per-client rate limits, request concurrency limits, and session limits. - Set session expiration and remove idle sessions. - Restrict GraphQL query complexity, depth, aliases, and requested result sizes where practical. - Record authenticated principal, tool name, target identifier, status, and quota-related failures in audit logs without logging credentials. 6. **Harden network deployment** - Keep the ...[truncated 193 chars]
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares no permissions, yet its documented behavior includes reading environment variables and making outbound network requests, including optional calls to The Graph gateway and fallback downloads from GitHub and Hugging Face. This creates a transparency and policy-enforcement gap: agents or operators may treat the skill as local-only while it can access secrets and external services under some execution paths.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
The skill description emphasizes discovery and opt-in querying, but the documented implementation also supports starting an HTTP/SSE server, exposing unauthenticated endpoints, serving manifests and compatibility endpoints, and downloading a database at runtime if missing. Even if some of this is optional, the mismatch increases the chance that operators deploy it with a broader attack surface than expected, leading to unintended local service exposure or runtime network fetches from external sources.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
* Exposes the classified subgraph registry as MCP tools that agents can call
 * to discover and select the right subgraph before querying The Graph.
 *
 * Tools:
 *   - search_subgraphs / recommend_subgraph / semantic_search_subgraphs: DISCOVERY only
 *   - get_subgraph_detail / list_registry_stats / get_schema_changes: local index
 *   - execute_query: opt-in POST of GraphQL to The Graph gateway
Confidence
84% confidence
Finding
The skill exposes powerful MCP tools, including execute_query and schema introspection, without any in-process authorization checks; any MCP client that can connect can invoke them. In HTTP/SSE mode, this matters more because a reachable unauthenticated client can spend the operator's configured Graph Studio API key and access remote data through the server as a confused deputy.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"author": "PaulieB14",
  "license": "MIT",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.29.0",
    "@xenova/transformers": "^2.17.2",
    "better-sqlite3": "^11.8.2",
    "express": "^4.21.0"
Confidence
88% confidence
Finding
The dependency is version-ranged with a caret, so fresh installs may resolve to newer minor/patch releases than were originally tested. That increases supply-chain and stability risk because a compromised or breaking upstream release could be pulled in without an explicit review, though package-lock usage may reduce practical exposure in some environments.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"license": "MIT",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.29.0",
    "@xenova/transformers": "^2.17.2",
    "better-sqlite3": "^11.8.2",
    "express": "^4.21.0"
  }
Confidence
88% confidence
Finding
Using a caret range for this package allows the installed artifact to drift over time as upstream publishes compatible releases. In an agent skill that bundles ML/runtime components, unexpected dependency changes can introduce vulnerable code paths or malicious supply-chain updates without any local source change.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"dependencies": {
    "@modelcontextprotocol/sdk": "^1.29.0",
    "@xenova/transformers": "^2.17.2",
    "better-sqlite3": "^11.8.2",
    "express": "^4.21.0"
  }
}
Confidence
90% confidence
Finding
This native-module dependency is also unpinned, meaning installations may fetch newer upstream patch/minor releases automatically. Because native dependencies can have significant security and build-surface implications, allowing version drift slightly increases supply-chain risk even though there is no evidence of active malicious intent here.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"@modelcontextprotocol/sdk": "^1.29.0",
    "@xenova/transformers": "^2.17.2",
    "better-sqlite3": "^11.8.2",
    "express": "^4.21.0"
  }
}
Confidence
90% confidence
Finding
Express is specified with a caret range, so deployments that install from package.json may pick up newer upstream releases than expected. For a server-capable MCP package, any automatically adopted vulnerable or malicious upstream release could affect network-facing request handling, making the unpinned dependency more relevant than in a purely local library.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
src/index.js:73