diff --git a/CLI.md b/CLI.md index 904b86b..bc21b8d 100644 --- a/CLI.md +++ b/CLI.md @@ -157,10 +157,12 @@ dxt unsign my-extension.dxt For signing extensions, you need: 1. **Certificate**: X.509 certificate in PEM format + - Should have Code Signing extended key usage - Can be self-signed (for development) or CA-issued (for production) 2. **Private Key**: Corresponding private key in PEM format + - Must match the certificate's public key 3. **Intermediate Certificates** (optional): For CA-issued certificates diff --git a/MANIFEST.md b/MANIFEST.md index 68d27c0..d1dab68 100644 --- a/MANIFEST.md +++ b/MANIFEST.md @@ -290,12 +290,14 @@ The `server` object defines how to run the MCP server: ### Server Types 1. **Python**: `server.type = "python"` + - Requires `entry_point` to Python file - All dependencies must be bundled in the DXT - Can use `server/lib` for packages or `server/venv` for full virtual environment - Python runtime version specified in `compatibility.runtimes.python` 2. **Node.js**: `server.type = "node"` + - Requires `entry_point` to JavaScript file - All dependencies must be bundled in `node_modules` - Node.js runtime version specified in `compatibility.runtimes.node` diff --git a/src/cli/unpack.ts b/src/cli/unpack.ts index d7f3afe..774ed6e 100644 --- a/src/cli/unpack.ts +++ b/src/cli/unpack.ts @@ -1,6 +1,6 @@ import { unzipSync } from "fflate"; import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; -import { join, resolve } from "path"; +import { join, resolve, sep } from "path"; import { extractSignatureBlock } from "../node/sign.js"; import { getLogger } from "../shared/log.js"; @@ -85,6 +85,17 @@ export async function unpackExtension({ if (Object.prototype.hasOwnProperty.call(decompressed, relativePath)) { const data = decompressed[relativePath]; const fullPath = join(finalOutputDir, relativePath); + + // Prevent zip slip attacks by validating the resolved path + const normalizedPath = resolve(fullPath); + const normalizedOutputDir = resolve(finalOutputDir); + if ( + !normalizedPath.startsWith(normalizedOutputDir + sep) && + normalizedPath !== normalizedOutputDir + ) { + throw new Error(`Path traversal attempt detected: ${relativePath}`); + } + const dir = join(fullPath, ".."); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true });