diff --git a/.gitignore b/.gitignore index 649949c..0247737 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ lib /runner src/plugins.ts +.claude/ # Created by https://www.toptal.com/developers/gitignore/api/node # Edit at https://www.toptal.com/developers/gitignore?templates=node diff --git a/dist/index.js b/dist/index.js index 900d796..6308257 100644 --- a/dist/index.js +++ b/dist/index.js @@ -83059,7 +83059,7 @@ function main() { yield (0, plugins_1.registerPlugins)(enablePlugins, tool.version); } catch (err) { - core.setFailed(err.message); + core.setFailed(err instanceof Error ? err.message : String(err)); } }); } @@ -83090,6 +83090,25 @@ exports.registerPlugins = registerPlugins; const shelljs_1 = __importDefault(__nccwpck_require__(1271)); const semver_1 = __importDefault(__nccwpck_require__(2597)); const node_fs_1 = __nccwpck_require__(3024); +/** + * Validates enablePlugins input to prevent command injection. + * Allows: 'true', 'false', or comma-separated plugin names (alphanumeric, underscore only). + */ +function validatePluginInput(input) { + // Allow 'true', 'false', or comma-separated identifiers (word characters only) + if (!/^(true|false|[\w]+(,[\w]+)*)$/i.test(input)) { + throw new Error(`Invalid enable-plugins input: "${input}". Only alphanumeric characters, underscores, and commas are allowed.`); + } +} +/** + * Validates version string to prevent command injection. + * Allows: alphanumeric, dots, hyphens (e.g., "0.95.0", "nightly-56ed69a"). + */ +function validateVersion(version) { + if (!/^[\w.-]+$/.test(version)) { + throw new Error(`Invalid version format: "${version}". Only alphanumeric characters, dots, and hyphens are allowed.`); + } +} const nu = String.raw; const pluginRegisterScript = nu ` #!/usr/bin/env nu @@ -83159,6 +83178,9 @@ function registerPlugins(enablePlugins, version) { if (enablePlugins === '' || enablePlugins === 'false') { return; } + // Validate inputs to prevent command injection + validatePluginInput(enablePlugins); + validateVersion(version); const LEGACY_VERSION = '0.92.3'; const script = 'register-plugins.nu'; const isLegacyVersion = !version.includes('nightly') && semver_1.default.lte(version, LEGACY_VERSION); diff --git a/src/index.ts b/src/index.ts index a688676..55aa6bd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -49,7 +49,7 @@ async function main() { console.log(`Current directory: ${process.cwd()}`); await registerPlugins(enablePlugins, tool.version); } catch (err) { - core.setFailed(err.message); + core.setFailed(err instanceof Error ? err.message : String(err)); } } diff --git a/src/plugins-tpl.ts b/src/plugins-tpl.ts index fb7b54c..a30abe8 100644 --- a/src/plugins-tpl.ts +++ b/src/plugins-tpl.ts @@ -2,6 +2,31 @@ import shell from 'shelljs'; import semver from 'semver'; import { promises as fs, constants as fs_constants } from 'node:fs'; +/** + * Validates enablePlugins input to prevent command injection. + * Allows: 'true', 'false', or comma-separated plugin names (alphanumeric, underscore only). + */ +function validatePluginInput(input: string): void { + // Allow 'true', 'false', or comma-separated identifiers (word characters only) + if (!/^(true|false|[\w]+(,[\w]+)*)$/i.test(input)) { + throw new Error( + `Invalid enable-plugins input: "${input}". Only alphanumeric characters, underscores, and commas are allowed.` + ); + } +} + +/** + * Validates version string to prevent command injection. + * Allows: alphanumeric, dots, hyphens (e.g., "0.95.0", "nightly-56ed69a"). + */ +function validateVersion(version: string): void { + if (!/^[\w.-]+$/.test(version)) { + throw new Error( + `Invalid version format: "${version}". Only alphanumeric characters, dots, and hyphens are allowed.` + ); + } +} + const nu = String.raw; const pluginRegisterScript = nu` @@ -12,6 +37,11 @@ export async function registerPlugins(enablePlugins: string, version: string) { if (enablePlugins === '' || enablePlugins === 'false') { return; } + + // Validate inputs to prevent command injection + validatePluginInput(enablePlugins); + validateVersion(version); + const LEGACY_VERSION = '0.92.3'; const script = 'register-plugins.nu'; const isLegacyVersion = !version.includes('nightly') && semver.lte(version, LEGACY_VERSION); diff --git a/src/plugins.ts b/src/plugins.ts index 33cc390..1762680 100644 --- a/src/plugins.ts +++ b/src/plugins.ts @@ -2,6 +2,31 @@ import shell from 'shelljs'; import semver from 'semver'; import { promises as fs, constants as fs_constants } from 'node:fs'; +/** + * Validates enablePlugins input to prevent command injection. + * Allows: 'true', 'false', or comma-separated plugin names (alphanumeric, underscore only). + */ +function validatePluginInput(input: string): void { + // Allow 'true', 'false', or comma-separated identifiers (word characters only) + if (!/^(true|false|[\w]+(,[\w]+)*)$/i.test(input)) { + throw new Error( + `Invalid enable-plugins input: "${input}". Only alphanumeric characters, underscores, and commas are allowed.` + ); + } +} + +/** + * Validates version string to prevent command injection. + * Allows: alphanumeric, dots, hyphens (e.g., "0.95.0", "nightly-56ed69a"). + */ +function validateVersion(version: string): void { + if (!/^[\w.-]+$/.test(version)) { + throw new Error( + `Invalid version format: "${version}". Only alphanumeric characters, dots, and hyphens are allowed.` + ); + } +} + const nu = String.raw; const pluginRegisterScript = nu` @@ -72,6 +97,11 @@ export async function registerPlugins(enablePlugins: string, version: string) { if (enablePlugins === '' || enablePlugins === 'false') { return; } + + // Validate inputs to prevent command injection + validatePluginInput(enablePlugins); + validateVersion(version); + const LEGACY_VERSION = '0.92.3'; const script = 'register-plugins.nu'; const isLegacyVersion = !version.includes('nightly') && semver.lte(version, LEGACY_VERSION);