security: fix 5 findings from issue #42 — env leak, ant gate, depth DoS, URL parse, CA cert

Finding 1 [CRITICAL] — sessionRunner leaks full process.env to child
Extract buildChildEnv() with an explicit allowlist of safe OS/runtime vars.
Child process no longer inherits ANTHROPIC_API_KEY, OPENAI_API_KEY, DB
credentials, or any other secret present in the parent shell environment.
Only CLAUDE_CODE_* bridge vars, PATH, HOME, and standard OS env are passed.

Finding 2 [HIGH] — USER_TYPE=ant activatable by external users
Add isAntEmployee() -> false constant in src/utils/buildConfig.ts.
Replace all three direct process.env.USER_TYPE === 'ant' checks in
setup.ts and onChangeAppState.ts so no external user can activate
Anthropic-internal code paths (commit attribution, system prompt clearing,
dangerously-skip-permissions bypass) by setting USER_TYPE in their shell.

Finding 3 [HIGH] — memoryScan.ts unlimited directory walk
Add MAX_DEPTH=3 guard on readdir({ recursive: true }) results.
Deep or symlink-looped memory directories no longer cause an unbounded
blocking walk before the MAX_MEMORY_FILES cap takes effect.

Finding 5 [HIGH] — buildSdkUrl uses string.includes for protocol detection
Replace apiBaseUrl.includes('localhost') with new URL(apiBaseUrl).hostname
comparison so a remote URL containing 'localhost' in its path no longer
incorrectly gets ws:// (unencrypted) instead of wss://.

Finding 6 [HIGH] — upstream proxy writes unvalidated CA cert to disk
Add isValidPemContent() validation before writeFile in the CA cert download
path. A compromised proxy sending non-PEM data (HTML, JSON, scripts) is now
rejected before it can be appended to the system CA bundle.

Each fix is covered by new unit tests (25 tests across 5 new test files).
All 52 tests pass. Build verified clean on v0.1.7.

Fixes #42

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gnanam1990
2026-04-02 21:04:10 +05:30
parent 3353101e83
commit 942d09ca9c
12 changed files with 363 additions and 24 deletions

View File

@@ -6,6 +6,7 @@ import {
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
logEvent,
} from 'src/services/analytics/index.js'
import { isAntEmployee } from 'src/utils/buildConfig.js'
import { getCwd } from 'src/utils/cwd.js'
import { checkForReleaseNotes } from 'src/utils/releaseNotes.js'
import { setCwd } from 'src/utils/Shell.js'
@@ -334,7 +335,7 @@ export async function setup(
// overhead. NOT an early-return: the --dangerously-skip-permissions safety
// gate, tengu_started beacon, and apiKeyHelper prefetch below must still run.
if (!isBareMode()) {
if (process.env.USER_TYPE === 'ant') {
if (isAntEmployee()) {
// Prime repo classification cache for auto-undercover mode. Default is
// undercover ON until proven internal; if this resolves to internal, clear
// the prompt cache so the next turn picks up the OFF state.
@@ -414,7 +415,7 @@ export async function setup(
}
if (
process.env.USER_TYPE === 'ant' &&
isAntEmployee() &&
// Skip for Desktop's local agent mode — same trust model as CCR/BYOC
// (trusted Anthropic-managed launcher intentionally pre-approving everything).
// Precedent: permissionSetup.ts:861, applySettingsChange.ts:55 (PR #19116)