Skip to content

Commit 83a0109

Browse files
7418claude
andcommitted
fix: sanitize env variables to prevent spawn EINVAL with third-party API providers
Strip null bytes and control characters from environment variable values before passing them to child_process.spawn via the SDK. Third-party Anthropic API providers could introduce invalid characters through api_key, base_url, or extra_env, causing spawn EINVAL errors. Bump version to 0.10.6. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 916b888 commit 83a0109

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codepilot",
3-
"version": "0.10.5",
3+
"version": "0.10.6",
44
"private": true,
55
"author": {
66
"name": "op7418",

src/lib/claude-client.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,28 @@ import os from 'os';
2424
import fs from 'fs';
2525
import path from 'path';
2626

27+
/**
28+
* Sanitize a string for use as an environment variable value.
29+
* Removes null bytes and control characters that cause spawn EINVAL.
30+
*/
31+
function sanitizeEnvValue(value: string): string {
32+
// eslint-disable-next-line no-control-regex
33+
return value.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
34+
}
35+
36+
/**
37+
* Sanitize all values in an env record so child_process.spawn won't
38+
* throw EINVAL due to invalid characters (null bytes, control chars).
39+
*/
40+
function sanitizeEnv(env: Record<string, string>): Record<string, string> {
41+
for (const [key, value] of Object.entries(env)) {
42+
if (typeof value === 'string') {
43+
env[key] = sanitizeEnvValue(value);
44+
}
45+
}
46+
return env;
47+
}
48+
2749
let cachedClaudePath: string | null | undefined;
2850

2951
function findClaudePath(): string | undefined {
@@ -262,7 +284,7 @@ export function streamClaude(options: ClaudeStreamOptions): ReadableStream<strin
262284
permissionMode: skipPermissions
263285
? 'bypassPermissions'
264286
: ((permissionMode as Options['permissionMode']) || 'acceptEdits'),
265-
env: sdkEnv,
287+
env: sanitizeEnv(sdkEnv),
266288
};
267289

268290
if (skipPermissions) {

0 commit comments

Comments
 (0)