{"record":{"id":"7431f17f769da684","repo":"affaan-m/ECC","slug":"binary-name-contains-unsafe-characters-binary","errorCode":null,"errorMessage":"Binary name contains unsafe characters: ${binary}","messagePattern":"Binary name contains unsafe characters: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/package-manager.js","lineNumber":335,"sourceCode":"  }\n}\n\n// Allowed characters in arguments: alphanumeric, whitespace, dashes, dots, slashes,\n// equals, colons, commas, quotes, @. Rejects shell metacharacters like ; | & ` $ ( ) { } < > !\nconst SAFE_ARGS_REGEX = /^[@a-zA-Z0-9\\s_./:=,'\"*+-]+$/;\n\n/**\n * Get the command to execute a package binary\n * @param {string} binary - Binary name (e.g., \"prettier\", \"eslint\")\n * @param {string} args - Arguments to pass\n * @throws {Error} If binary name or args contain unsafe characters\n */\nfunction getExecCommand(binary, args = '', options = {}) {\n  if (!binary || typeof binary !== 'string') {\n    throw new Error('Binary name must be a non-empty string');\n  }\n  if (!SAFE_NAME_REGEX.test(binary)) {\n    throw new Error(`Binary name contains unsafe characters: ${binary}`);\n  }\n  if (args && typeof args === 'string' && !SAFE_ARGS_REGEX.test(args)) {\n    throw new Error(`Arguments contain unsafe characters: ${args}`);\n  }\n\n  const pm = getPackageManager(options);\n  return `${pm.config.execCmd} ${binary}${args ? ' ' + args : ''}`;\n}\n\n/**\n * Interactive prompt for package manager selection\n * Returns a message for Claude to show to user\n *\n * NOTE: Does NOT spawn child processes to check availability.\n * Lists all supported PMs and shows how to configure preference.\n */\nfunction getSelectionPrompt() {\n  let message = '[PackageManager] No package manager preference detected.\\n';","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/package-manager.js#L317-L353","documentation":"getExecCommand() validates the binary name against SAFE_NAME_REGEX before building the shell command. This error is thrown when the binary is a proper non-empty string but contains characters outside the safe allowlist (spaces, '/', path separators in some forms, quotes, ';', '$()', etc.). It exists to stop untrusted binary names from injecting shell commands.","triggerScenarios":"Calling getExecCommand with a binary value containing metacharacters or whitespace: getExecCommand('prettier --write'), getExecCommand('node -e x'), getExecCommand('/usr/bin/tool; rm -rf /'), getExecCommand('tool`id`').","commonSituations":"Concatenating a binary name with its arguments into one string; putting a full path with spaces into the binary slot; forwarding user-controlled input (CLI arg, config) as the binary; attempting to run inline scripts via 'node -e' or 'sh -c' through this API instead of a dedicated spawn API.","solutions":["Pass only the bare binary token ('prettier', 'eslint') and move arguments to the args parameter (validated separately).","Remove shell metacharacters from the value; check the offending name in the error message.","If you need a specific binary path, use an API that accepts an absolute path or executable directly rather than embedding flags/paths with spaces here.","Sanitize at the boundary: validate tool names from config/user input with the same allowlist before calling."],"exampleFix":"// before\ngetExecCommand(`node ${scriptPath} --fix`)\n// after\ngetExecCommand('node', `${scriptPath} --fix`) // args validated by SAFE_ARGS_REGEX","handlingStrategy":"validation","validationCode":"const SAFE_BINARY = /^[A-Za-z0-9._-]+$/;\nif (!SAFE_BINARY.test(binary)) {\n  throw new Error(`Unsafe binary name: ${binary}`);\n}\ngetExecCommand(binary, args);","typeGuard":"function isSafeBinaryName(v) {\n  return typeof v === 'string' && /^[A-Za-z0-9._-]+$/.test(v);\n}","tryCatchPattern":"try {\n  const cmd = getExecCommand(binary, args);\n} catch (e) {\n  if (String(e.message).startsWith('Binary name contains unsafe characters')) {\n    console.error(`Split '${binary}' into a bare binary plus args before calling.`);\n  } else throw e;\n}","preventionTips":["Keep binary and arguments as separate parameters — never embed flags in the binary token.","Avoid inline 'node -e' / 'sh -c' style invocations through this API.","Validate any config- or user-supplied tool name against an allowlist at the boundary.","Watch for paths with spaces; use the library's supported path mechanism, not the binary slot."],"tags":["validation","shell-injection-prevention","package-manager","argument-sanitization"],"backgroundTag":"invalid-identifier-format","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}