inspector/server/package.json
manjunathbhaskar 9140789869 fix: prevent DNS-rebinding TOCTOU in safeProxyFetch by pinning resolved IPs
Previously assertSafeProxyTarget resolved the target hostname and validated
the IPs, but safeProxyFetch then passed the raw URL to node-fetch, which
performed its own DNS lookup. In the window between the two resolutions an
attacker who controls the domain's TTL could flip the record to
169.254.169.254 (cloud-metadata), causing fetch() to connect to the instance-
metadata service even though the block-list check passed.

Fix: assertSafeProxyTarget now returns the validated IP addresses. On each
hop of safeProxyFetch we call createPinnedAgent() to build an http/https.Agent
whose lookup hook unconditionally returns the pre-validated IP. node-fetch
uses that hook instead of the OS resolver, closing the TOCTOU window entirely.

Refactoring: isBlockedProxyAddress, assertSafeProxyTarget, and the new
createPinnedAgent are extracted to server/src/proxy-security.ts so they can
be unit-tested in isolation. A vitest suite is added to the server package
(the first unit tests for this package) with 26 cases covering the block-list,
DNS validation, IP-pinning, and the TOCTOU guarantee itself.
2026-07-21 12:46:25 +02:00

52 lines
1.4 KiB
JSON

{
"name": "@modelcontextprotocol/inspector-server",
"version": "1.0.0",
"description": "Server-side application for the Model Context Protocol inspector",
"license": "SEE LICENSE IN LICENSE",
"author": "Model Context Protocol a Series of LF Projects, LLC.",
"homepage": "https://modelcontextprotocol.io",
"bugs": "https://github.com/modelcontextprotocol/inspector/issues",
"repository": {
"type": "git",
"url": "https://github.com/modelcontextprotocol/inspector",
"directory": "server"
},
"type": "module",
"bin": {
"mcp-inspector-server": "build/index.js"
},
"files": [
"build",
"static",
"LICENSE"
],
"scripts": {
"build": "tsc && shx cp -R static build",
"start": "node build/index.js",
"dev": "tsx watch --clear-screen=false src/index.ts",
"dev:windows": "tsx watch --clear-screen=false src/index.ts < NUL",
"test": "vitest run",
"test:watch": "vitest"
},
"devDependencies": {
"@types/cors": "^2.8.19",
"@types/express": "^5.0.0",
"@types/node": "^22.0.0",
"@types/shell-quote": "^1.7.5",
"@types/ws": "^8.5.12",
"tsx": "^4.19.0",
"typescript": "^5.6.2",
"vitest": "^4.1.0"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.25.2",
"cors": "^2.8.5",
"express": "^5.1.0",
"shell-quote": "^1.8.4",
"shx": "^0.3.4",
"spawn-rx": "^5.1.2",
"ws": "^8.18.0",
"zod": "^3.25.76",
"express-rate-limit": "^8.2.1"
}
}