Repository navigation
JS: Add models for the MCP server SDKs and flow summaries for zod - #22749
Alex-Hofer wants to merge 5 commits into
Conversation
|
Thanks for your contribution @Alex-Hofer. We discussed this internally and think |
Callback arguments and low-level requests are produced by a language model, so they are sources of the opt-in ai threat model added in github#22810. Request headers and bearer tokens come from the HTTP client and stay sources of the remote threat model.
862d2f5 to
3460d05
Compare
|
Done: the rows for handler input (callback arguments, low-level requests) now use |
|
Thanks for starting the checks! The coverage check failed while setting up Python 3.8, which the Ubuntu 26.04 runners no longer have; main moved that workflow to Python 3.12 in 104bf77, and a re-run reuses the old merge commit. I have merged main into the branch (no force-push), so the next run should pick up the fix. The coverage report only covers Java, C# and Go, so the change itself does not affect it. |
ModelOutput::getAWarning reports source models whose kind is not listed in ValidSourceKind. The list did not include ai, added to the threat models in github#22810, so the rows of this PR showed up as warnings in library-tests/frameworks/data.
|
I can't open the internal run, but I think I found what failed in The commit touches |
Follow-up to #22702; #22703 proposes the same for Python.
MCP servers expose tools to LLM agents. Every argument of a tool, resource or prompt callback is chosen by the client, that is by a model that prompt injection can steer, or by anyone who can reach the server over HTTP. This PR models that input for the TypeScript SDKs as data extensions in
javascript/ql/lib/ext: the callback arguments and the low-level requests as sources of the opt-inaithreat model (#22810), the request headers and the bearer token as sources of theremotethreat model.First commit, the MCP SDKs:
@modelcontextprotocol/sdk1.x and@modelcontextprotocol/server2.x,McpServer: the arguments of the callbacks oftool,registerTool,promptandregisterPrompt, and the URI and template variables ofresourceandregisterResource.Server:request.paramsin handlers ofsetRequestHandler, also when the server is reached throughMcpServer.server, and the parameters of custom methods in 2.x.extra.requestInfo.headersandextra.authInfo.tokenin 1.x,ctx.http.req.headers.get()andctx.http.authInfo.tokenin 2.x.fastmcp:addTool({execute}),addResourceTemplate({load}),addPrompt({load}).typeModelrows for the import paths with and without.jsand for a server that arrives as a typed parameter.Second commit, flow summaries for
zod(independent of the first, can be split off): handlers of the low-level server get the raw arguments and validate them with a zod schema before use (Schema.parse(request.params.arguments)). There is no model of zod, so the flow ends at that call. Four rows let data flow from the argument ofparse,safeParse,parseAsyncandsafeParseAsyncto the result. I used kindvalue:js/path-injectiondoes not follow ataintsummary there (it is a data-flow configuration with flow states) and does follow avalueone; I checked both on a small server.Tests:
library-tests/threat-models/sourcesgetsmcp.ts,fastmcp.tsandzod.tswith inline expectations (threat-source,hasFlow); callbacks that are not registered with a server and a static resource have none.codeql test runpasses locally with CLI 2.27.1.Evidence: as a model pack, these rows take CodeQL 2.27.1 from 6 to 25 of 38 real, publicly disclosed vulnerabilities in TypeScript and JavaScript MCP servers in mcp-vulnbench. On the half of the cases that the models were not run on while they were written, plain CodeQL finds 3 of 21, the rows of the first commit 11, and both commits together 14 (the zod rows were measured with kind
taint), at 2.62 instead of 0.08 alarms per KLOC. Known limits are documented there: servers kept in a field of a project class, handler tables built across modules, and sinks such asfetchfromundicior Playwright'spage.goto. The measurement used the rows asremote, which is on by default; withaithe same sources apply once that threat model is enabled.