{"record":{"id":"4388a6a5809a020e","repo":"affaan-m/ECC","slug":"executable-must-be-a-non-empty-argv-entry-without","errorCode":null,"errorMessage":"Executable must be a non-empty argv entry without control bytes.","messagePattern":"Executable must be a non-empty argv entry without control bytes\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/terminal-opener/scripts/open-terminal.js","lineNumber":53,"sourceCode":"\nfunction isAbsolutePath(value) {\n  return path.isAbsolute(value) || path.win32.isAbsolute(value);\n}\n\nfunction validateTerminalName(value) {\n  if (!/^[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(value)) {\n    throw new Error('Invalid terminal name; use a simple adapter name such as wezterm.');\n  }\n}\n\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  }","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/terminal-opener/scripts/open-terminal.js#L35-L71","documentation":"validateExecutable rejects an empty executable or one containing NUL (\\0), CR (\\r), or LF (\\n) control bytes. These would break argv handling or enable line-splitting injection. This is the first executable check, run before the shell-command-string detection at lines 62-71.","triggerScenarios":"options.executable is '' (e.g. '--' immediately followed by another '--' or end of args producing an empty token) or contains \\0/\\r/\\n. validateExecutable is called from parseArgs when an executable is present.","commonSituations":"Passing an empty executable; a template literal that introduced a newline into the executable name; binary/corrupted argv; accidentally putting a flag where the executable goes.","solutions":["Provide a non-empty executable token after -- with no control bytes.","If the executable comes from a template, sanitize it: strip \\0, \\r, \\n.","Double-check the token order: executable first, then its arguments."],"exampleFix":"// before\nparseArgs(['--', '', 'arg']); // empty executable\n\n// after\nparseArgs(['--', '/bin/echo', 'arg']);","handlingStrategy":"validation","validationCode":"function safeExecutable(value) {\n  if (!value || /[\\0\\r\\n]/.test(value)) {\n    throw new Error('Executable must be non-empty with no control bytes');\n  }\n  return value;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass the executable as a distinct argv token, not interpolated from a template that may inject newlines.","Reject empty executable tokens early in any wrapper that builds argv."],"tags":["validation","security","terminal","executable"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}