Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ This project follows Semantic Versioning. Release notes describe protocol suppor
- Initial TypeScript MCP server template.
- HTTP: a request with a malformed `Host` header or request target no longer crashes the process.
- HTTP: the MCP endpoint validates `Host` and `Origin` headers against `MCP_ALLOWED_HOSTS` and `MCP_ALLOWED_ORIGINS` (localhost by default) to block DNS rebinding.
- Build: `npm run verify` (and therefore CI) runs the privacy check, which now also catches unescaped Windows profile paths.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"build": "tsc -p tsconfig.build.json",
"check": "tsc --noEmit",
"check:package": "node scripts/check-generated.mjs",
"check:privacy": "node scripts/privacy-check.mjs",
"clean": "node scripts/clean.mjs",
"dev": "tsx watch src/cli.ts",
"format": "prettier --check .",
Expand All @@ -20,7 +21,7 @@
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest",
"verify": "npm run format && npm run lint && npm run check && npm run test:coverage && npm run build && npm run check:package"
"verify": "npm run check:privacy && npm run format && npm run lint && npm run check && npm run test:coverage && npm run build && npm run check:package"
},
"dependencies": {
"@modelcontextprotocol/node": "2.0.0",
Expand Down
11 changes: 9 additions & 2 deletions scripts/privacy-check.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import { execFileSync } from "node:child_process";
import { readFile } from "node:fs/promises";
import process from "node:process";

const patterns = ["C:\\\\Users\\\\", "/Users/", "/home/", "BEGIN PRIVATE KEY", "api_key="];
// Match Windows profile paths written with single (C:\Users\) or JSON-escaped (C:\\Users\\) separators.
const patterns = [
/[A-Za-z]:\\{1,2}Users\\{1,2}/,
/\/Users\//,
/\/home\//,
/BEGIN PRIVATE KEY/,
/api_key=/,
];
const tracked = execFileSync("git", ["ls-files", "-z"], { encoding: "utf8" })
.split("\0")
.filter(Boolean);
Expand All @@ -11,7 +18,7 @@ for (const pattern of patterns) {
for (const path of tracked) {
if (path.endsWith("privacy-check.mjs")) continue;
try {
if ((await readFile(path, "utf8")).includes(pattern)) matches.push(path);
if (pattern.test(await readFile(path, "utf8"))) matches.push(path);
} catch {
// Binary and inaccessible files do not participate in the text scan.
}
Expand Down
Loading