{"record":{"id":"e442133f5c619368","repo":"affaan-m/ECC","slug":"executable-must-be-one-argv-entry-not-an-interpol","errorCode":null,"errorMessage":"Executable must be one argv entry, not an interpolated shell command string.","messagePattern":"Executable must be one argv entry, not an interpolated shell command string\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/terminal-opener/scripts/open-terminal.js","lineNumber":63,"sourceCode":"\nfunction validateCwd(value) {\n  if (value.includes('\\0')) throw new Error('--cwd must not contain a NUL byte.');\n  if (!isAbsolutePath(value)) throw new Error('--cwd must be an absolute path.');\n}\n\nfunction validateExecutable(value) {\n  if (!value || /[\\0\\r\\n]/.test(value)) {\n    throw new Error('Executable must be a non-empty argv entry without control bytes.');\n  }\n\n  const whitespaceIndex = value.search(/\\s/);\n  const separatorIndexes = [value.indexOf('/'), value.indexOf('\\\\')].filter(index => index >= 0);\n  const firstSeparatorIndex = separatorIndexes.length > 0 ? Math.min(...separatorIndexes) : -1;\n  const resemblesExecutablePath = isAbsolutePath(value)\n    || (firstSeparatorIndex >= 0 && (whitespaceIndex < 0 || firstSeparatorIndex < whitespaceIndex));\n\n  if (whitespaceIndex >= 0 && !resemblesExecutablePath) {\n    throw new Error(\n      'Executable must be one argv entry, not an interpolated shell command string.'\n    );\n  }\n  if (!resemblesExecutablePath && /[;&|<>`$]/.test(value)) {\n    throw new Error(\n      'Executable must be one argv entry, not an interpolated shell command string.'\n    );\n  }\n}\n\nfunction validateArgv(argv) {\n  for (const argument of argv) {\n    if (argument.includes('\\0')) throw new Error('Arguments must not contain NUL bytes.');\n  }\n}\n\nfunction readValue(argv, index, option) {\n  const value = argv[index + 1];","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/terminal-opener/scripts/open-terminal.js#L45-L81","documentation":"validateExecutable computes whether the value 'resembles an executable path' (it is absolute, or a path separator appears before any whitespace). If the value contains whitespace AND does not resemble a path, it is rejected. Rationale: launch always uses shell:false, so a whitespace-laden token is passed as one bogus argv entry rather than parsed as a command. This is the whitespace branch (line 62-65).","triggerScenarios":"options.executable contains whitespace and is not path-like — e.g. a single token 'bash -c echo hi' passed as the executable. The executable slot should hold one argv entry only.","commonSituations":"Passing a shell command string instead of separating the executable and its args after --; copy-pasting a command line into the executable argument.","solutions":["Put the executable as the first token after --, and pass each argument as its own token after that.","If you genuinely need a shell command, invoke a shell explicitly: -- /bin/sh -c '<command>' (sh becomes the executable, -c and the string become args)."],"exampleFix":"# before\nnode open-terminal.js -- \"bash -c 'echo hi'\"\n\n# after\nnode open-terminal.js -- bash -c \"echo hi\"","handlingStrategy":"validation","validationCode":"function isSingleArgvEntry(executable) {\n  if (!executable) return false;\n  const sep = [executable.indexOf('/'), executable.indexOf('\\\\')].filter(i => i >= 0);\n  const firstSep = sep.length ? Math.min(...sep) : -1;\n  const ws = executable.search(/\\s/);\n  const pathLike = path.isAbsolute(executable) || (firstSep >= 0 && (ws < 0 || firstSep < ws));\n  return !ws || pathLike;\n}\nif (!isSingleArgvEntry(executable)) {\n  throw new Error('Pass executable and args as separate tokens after --');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never interpolate a shell command into the executable slot; tokenize it.","If you need shell semantics, invoke /bin/sh -c explicitly as executable + args.","Build argv programmatically (an array) instead of splitting a command string."],"tags":["validation","security","terminal","argument-injection"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}