{"record":{"id":"ed8393c75444f5ed","repo":"paperclipai/paperclip","slug":"invalid-sandbox-environment-variable","errorCode":null,"errorMessage":"Invalid sandbox environment variable.","messagePattern":"Invalid sandbox environment variable\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/createos/src/execute.ts","lineNumber":21,"sourceCode":"import { setTimeout as delay } from \"node:timers/promises\";\nimport type { PluginEnvironmentExecuteParams, PluginEnvironmentExecuteResult } from \"@paperclipai/plugin-sdk\";\nimport { CreateosApiError, CreateosClient, identifier, object } from \"./client.js\";\n\nconst MAX_LINE_BYTES = 1_048_576;\nconst MAX_CAPTURE_CHARS = 4_194_304;\n\nexport class CreateosCleanupError extends Error {}\n\nexport function shellQuote(value: string): string {\n  if (value.includes(\"\\0\")) throw new Error(\"Sandbox command values cannot contain NUL.\");\n  return `'${value.replace(/'/g, `'\"'\"'`)}'`;\n}\n\nfunction commandScript(params: PluginEnvironmentExecuteParams, stdinPath: string | null): string {\n  if (!params.command) throw new Error(\"A sandbox command is required.\");\n  const env = Object.entries(params.env ?? {}).map(([key, value]) => {\n    if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) || typeof value !== \"string\") {\n      throw new Error(\"Invalid sandbox environment variable.\");\n    }\n    return `${key}=${shellQuote(value)}`;\n  });\n  const command = [params.command, ...(params.args ?? [])].map(shellQuote).join(\" \");\n  return [\n    params.cwd ? `cd -- ${shellQuote(params.cwd)} || exit` : \"\",\n    `exec env ${env.join(\" \")} ${command}${stdinPath ? ` < ${shellQuote(stdinPath)}` : \"\"}`,\n  ].filter(Boolean).join(\"\\n\");\n}\n\nasync function* events(response: Response): AsyncGenerator<Record<string, unknown>> {\n  if (!response.body) throw new Error(\"CreateOS returned an empty process stream.\");\n  const reader = response.body.getReader();\n  const decoder = new TextDecoder();\n  let pending = \"\";\n  try {\n    for (;;) {\n      const { value, done } = await reader.read();","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/createos/src/execute.ts#L3-L39","documentation":"commandScript validates every entry in params.env: keys must match /^[A-Za-z_][A-Za-z0-9_]*$/ (a valid POSIX shell identifier) and values must be strings. Anything else — keys starting with a digit, containing dashes/dots/spaces, or non-string values — is rejected to guarantee the generated 'KEY=value' shell lines are safe.","triggerScenarios":"Calling execute with params.env containing a key like '1PATH', 'MY-VAR', 'my.var', or an empty key, or a value that is a number, boolean, object, or undefined.","commonSituations":"Passing through process.env from a context with odd vars (e.g. npm_lifecycle_event-like keys with dashes); passing structured config values (numbers/objects) without String() conversion; forwarding env maps from other tools with dotted keys.","solutions":["Rename env keys to valid shell identifiers: letters, digits, underscores, not starting with a digit.","Coerce values with String(value) before passing them in env.","Drop or whitelist unsupported keys before calling execute, e.g. Object.fromEntries(entries.filter(([k, v]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(k) && typeof v === 'string'))."],"exampleFix":"// before\nexec({ command: \"make\", env: { \"BUILD-ID\": 42 } })\n// after\nexec({ command: \"make\", env: { BUILD_ID: \"42\" } })","handlingStrategy":"validation","validationCode":"const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\nfunction sanitizeEnv(env) {\n  return Object.fromEntries(\n    Object.entries(env ?? {}).filter(([k, v]) => ENV_KEY_RE.test(k) && typeof v === 'string')\n      .map(([k, v]) => [k, String(v)])\n  );\n}","typeGuard":"function isShellSafeEnv(env) {\n  return Object.entries(env ?? {}).every(([k, v]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(k) && typeof v === 'string');\n}","tryCatchPattern":null,"preventionTips":["Whitelist the env vars you forward instead of passing process.env wholesale","Coerce values to strings before passing structured data","Keep env keys shell-identifier-safe by convention (no dashes or dots)"],"tags":["env-vars","validation","shell","identifier-format"],"backgroundTag":"invalid-identifier-format","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}