diff --git a/package-lock.json b/package-lock.json index e31bccacc0a..7b135587bbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -210,7 +210,6 @@ "version": "7.28.4", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -249,7 +248,6 @@ "version": "6.3.1", "dev": true, "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" } @@ -284,7 +282,6 @@ "version": "7.27.2", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", @@ -300,7 +297,6 @@ "version": "6.3.1", "dev": true, "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" } @@ -329,7 +325,6 @@ "version": "7.28.3", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", @@ -376,7 +371,6 @@ "version": "7.28.4", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" @@ -2188,7 +2182,6 @@ "version": "2.3.5", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -5719,6 +5712,7 @@ "node_modules/@octokit/core": { "version": "7.0.5", "license": "MIT", + "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.2", @@ -5861,6 +5855,7 @@ "node_modules/@opentelemetry/api": { "version": "1.8.0", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -6907,6 +6902,7 @@ "version": "4.1.12", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/ms": "*" } @@ -7051,6 +7047,7 @@ "node_modules/@types/node": { "version": "22.18.11", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -7344,6 +7341,7 @@ "version": "8.45.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.45.0", "@typescript-eslint/types": "8.45.0", @@ -8494,6 +8492,7 @@ "node_modules/acorn": { "version": "8.15.0", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -8538,6 +8537,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -8931,7 +8931,6 @@ "version": "2.8.7", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "baseline-browser-mapping": "dist/cli.js" } @@ -9522,8 +9521,7 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "CC-BY-4.0", - "peer": true + "license": "CC-BY-4.0" }, "node_modules/caseless": { "version": "0.12.0", @@ -10913,8 +10911,7 @@ "node_modules/electron-to-chromium": { "version": "1.5.223", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/emoji-regex": { "version": "10.6.0", @@ -11182,6 +11179,7 @@ "version": "9.36.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -12564,7 +12562,6 @@ "version": "1.0.0-beta.2", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -14100,7 +14097,6 @@ "version": "2.2.3", "dev": true, "license": "MIT", - "peer": true, "bin": { "json5": "lib/cli.js" }, @@ -14734,7 +14730,6 @@ "version": "5.1.1", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "yallist": "^3.0.2" } @@ -15294,8 +15289,7 @@ "node_modules/node-releases": { "version": "2.0.21", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/node-source-walk": { "version": "7.0.1", @@ -16112,6 +16106,7 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.12.0", "pg-pool": "^3.13.0", @@ -16335,6 +16330,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -17098,6 +17094,7 @@ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -18346,12 +18343,14 @@ }, "node_modules/tslib": { "version": "2.8.1", - "license": "0BSD" + "license": "0BSD", + "peer": true }, "node_modules/tsx": { "version": "4.20.6", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" @@ -18426,6 +18425,7 @@ "node_modules/typescript": { "version": "5.8.3", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18736,7 +18736,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -19235,6 +19234,7 @@ "version": "6.4.1", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -19329,6 +19329,7 @@ "version": "3.2.4", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -19877,8 +19878,7 @@ "node_modules/yallist": { "version": "3.1.1", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/yaml": { "version": "2.8.3", diff --git a/src/commands/functions/functions-create.ts b/src/commands/functions/functions-create.ts index 42d5da8eded..80894266327 100644 --- a/src/commands/functions/functions-create.ts +++ b/src/commands/functions/functions-create.ts @@ -394,7 +394,9 @@ const downloadFromURL = async function (command, options, argumentName, function folderContents.map(async ({ download_url: downloadUrl, name }) => { try { const res = await fetch(downloadUrl) - const finalName = path.basename(name, '.js') === functionName ? `${nameToUse}.js` : name + const finalName = path.basename(name, '.js') === functionName + ? `${nameToUse}.js` + : path.basename(name) // ← strip any directory components const dest = fs.createWriteStream(path.join(fnFolder, finalName)) res.body?.pipe(dest) } catch (error_) { @@ -744,14 +746,20 @@ const registerEFInToml = async (funcName, options) => { * @returns */ // @ts-expect-error TS(7006) FIXME: Parameter 'functionsDir' implicitly has an 'any' t... Remove this comment to see the full error message -const ensureFunctionPathIsOk = function (functionsDir, name) { - const functionPath = path.join(functionsDir, name) - if (fs.existsSync(functionPath)) { - log(`${NETLIFYDEVLOG} Function ${functionPath} already exists, cancelling...`) - process.exit(1) + const ensureFunctionPathIsOk = function (functionsDir, name) { + // Prevent path traversal: reject names like "../../evil" + const resolvedFunctionsDir = path.resolve(functionsDir) + const functionPath = path.join(resolvedFunctionsDir, name) + if (!functionPath.startsWith(resolvedFunctionsDir + path.sep)) { + log(`${NETLIFYDEVERR} Invalid function name: "${name}" resolves outside the functions directory.`) + process.exit(1) + } + if (fs.existsSync(functionPath)) { + log(`${NETLIFYDEVLOG} Function ${functionPath} already exists, cancelling...`) + process.exit(1) + } + return functionPath } - return functionPath -} // Scans `functions-templates/` for a template whose `.mjs` metadata // `name` matches. Returns its `functionType` and the language folder it lives