Three security hardening fixes from /ship adversarial review:
1. AUTH_TOKEN unicode-whitespace bypass (server.ts:67-83).
Old: `process.env.AUTH_TOKEN?.trim() || randomUUID()` only stripped
ASCII whitespace. A misconfigured embedder shipping AUTH_TOKEN=$''
(BOM) or $'' (zero-width space) would silently get a
one-character bearer secret. New `sanitizeAuthToken()` strips all
unicode whitespace via regex and requires >= 16 chars after stripping;
anything shorter falls back to crypto.randomUUID(). Same sanitizer
used by `resolveConfigFromEnv()` so the embedder path is hardened too.
2. security-classifier.ts checkTranscript safety net.
`resolveClaudeCommand()` and `spawn()` can throw under transient
conditions (PATH probe failure, posix_spawn ENOMEM). Old code let the
throw propagate and rejected the Promise with a raw exception. Now
wrapped in try/catch that calls finish() with a degraded signal,
matching the graceful-degradation contract the layer already promises
for missing-CLI / exit-nonzero / parse-error.
3. cleanSingletonLocks defensive guard tightened (config.ts).
Old: basename === 'chromium-profile' OR userDataDir === $CHROMIUM_PROFILE.
The second branch was env-controlled and the first was bypassable by
passing a relative path that resolved to chromium-profile via CWD
drift. New guard: refuses relative paths outright, resolves both
sides via path.resolve(), and only accepts the env-match path when
$CHROMIUM_PROFILE is itself absolute.
Test updates: replace the old `.trim()` test with three new cases
covering unicode-whitespace stripping, short-token rejection, and
zero-width-only rejection (server-factory.test.ts).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>