Skip to content

fix: security audit remediation — 12 fixes, 20 tests (v0.13.1.0)#595

Open
garrytan wants to merge 10 commits intomainfrom
garrytan/fix-security-issues
Open

fix: security audit remediation — 12 fixes, 20 tests (v0.13.1.0)#595
garrytan wants to merge 10 commits intomainfrom
garrytan/fix-security-issues

Conversation

@garrytan
Copy link
Copy Markdown
Owner

Summary

Independent security audit found 10 issues (2 critical, 4 high, 4 medium). All fixed, plus 2 additional issues found by Codex adversarial red team. 4 AI review passes (2 outside voice + 2 adversarial from both Codex and Claude).

Auth hardening:

  • Token removed from /health response. Extension bootstraps via .auth.json file
  • Bearer auth required on all cookie-picker data/action routes
  • Auth + no wildcard CORS on /refs, /activity/stream, /activity/history
  • getToken handler removed from extension

Data protection:

  • State files get 7-day TTL with warning on load, auto-cleanup on startup
  • Plaintext cookie warning on state save

XSS prevention:

  • innerHTML replaced with textContent/createElement in content.js
  • entry.command escaped with escapeHtml() in sidepanel.js (Codex adversarial finding)

Path validation:

  • validateReadPath rewritten: always resolves to absolute, uses realpathSync, handles macOS /tmp symlink
  • Freeze hook: POSIX path resolution + trailing slash prefix collision fix

Shell injection:

  • gstack-config: key validation, grep -F, sed escaping, newline dropping
  • gstack-telemetry-log: json_safe() on REPO_SLUG and BRANCH

Test Coverage

20 new security regression tests across 7 test files. All pass.

Pre-Landing Review

Eng review ran during planning (CLEAR). Pre-landing review via /ship.

Adversarial Review

4 passes: Codex outside voice + Claude outside voice + Codex adversarial + Claude adversarial. Codex adversarial found 2 additional issues (sidepanel XSS, freeze prefix collision) — both fixed.

Plan Completion

All 10 audit findings + 2 adversarial findings addressed. 20 tests written (plan specified 20).

Test plan

  • All security tests pass (20 new tests)
  • All existing tests pass (pre-existing failures only)
  • Tests run on merged code (main merged before testing)

🤖 Generated with Claude Code

garrytan and others added 10 commits March 27, 2026 22:13
…ICAL-02 + HIGH-03)

- Remove token from /health response (was leaked to any localhost process)
- Write .auth.json to extension dir for Manifest V3 bootstrap
- sidebar-agent reads token from state file via BROWSE_STATE_FILE env var
- Remove getToken handler from extension (token via health broadcast)
- Extension loads token before first health poll to prevent race condition
- Add Bearer token auth gate on all /cookie-picker/* data/action routes
- GET /cookie-picker HTML page stays unauthenticated (UI shell)
- Token embedded in served HTML for picker's fetch calls
- CORS preflight now allows Authorization header
- Add savedAt timestamp to state save output
- Warn on load if state file older than 7 days
- Auto-delete stale state files (>7 days) on server startup
- Warning about plaintext cookie storage in save message
- content.js: replace innerHTML with createElement/textContent for ref panel
- sidepanel.js: escape entry.command with escapeHtml() in activity feed
- Both found by security audit + Codex adversarial red team
- Always resolve to absolute path first (fixes relative path bypass)
- Use realpathSync to follow symlinks before boundary check
- Throw on non-ENOENT realpathSync failures (explicit over silent)
- Resolve SAFE_DIRECTORIES through realpathSync (macOS /tmp → /private/tmp)
- Resolve directory part for non-existent files (ENOENT with symlinked parent)
- Add POSIX-portable path resolution (cd + pwd -P, works on macOS)
- Fix prefix collision: /project-evil no longer matches /project freeze dir
- Use trailing slash in boundary check to require directory boundary
- gstack-config: validate keys (alphanumeric+underscore only)
- gstack-config: use grep -F (fixed string) instead of -E (regex)
- gstack-config: escape sed special chars in values, drop newlines
- gstack-telemetry-log: sanitize REPO_SLUG and BRANCH via json_safe()
- server-auth: verify token removed from /health, auth on /refs, /activity/*
- cookie-picker: auth required on data routes, HTML page unauthenticated
- path-validation: symlink bypass blocked, realpathSync failure throws
- gstack-config: regex key rejected, sed special chars preserved
- state-ttl: savedAt timestamp, 7-day TTL warning
- telemetry: branch/repo with quotes don't corrupt JSON
- adversarial: sidepanel escapes entry.command, freeze prefix collision
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

E2E Evals: ✅ PASS

8/8 tests passed | $.99 total cost | 12 parallel runners

Suite Result Status Cost
e2e-browse 2/2 $0.13
e2e-deploy 2/2 $0.25
e2e-qa-workflow 1/1 $0.34
llm-judge 1/1 $0.02
e2e-deploy 2/2 $0.25

12x ubicloud-standard-2 (Docker: pre-baked toolchain + deps) | wall clock ≈ slowest suite

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant