feat(security): GitHub App integration with token disclosure hardening#27
Merged
electronicBlacksmith merged 6 commits intomainfrom Apr 15, 2026
Merged
Conversation
Add src/integrations/github-app.ts with: - Zod-validated env var loading (GITHUB_APP_ID, GITHUB_APP_CLIENT_ID, GITHUB_APP_INSTALLATION_ID, GITHUB_APP_PRIVATE_KEY_B64) - Installation token caching with automatic refresh 5 min before expiry - @octokit/auth-app for GitHub App authentication - validateGitHubAppEnv() for doctor checks without token minting Design: Lazy loading means Phantom boots without GitHub access. First call to getInstallationToken() fails with a clear error if env vars are missing.
Add phantom_gh_exec tool for authenticated GitHub operations: - Runs gh/git commands with GH_TOKEN injected via subprocess env - Token never appears in model context or tool results - Shell metacharacter validation prevents injection attacks - Args passed as array to Bun.spawn (no shell interpretation) Extend buildSafeEnv() to accept explicit env vars (GH_TOKEN). Wire createGitHubToolServer() into index.ts MCP factories.
Add checkGitHubApp() to phantom doctor: - Checks for GITHUB_APP_ID, GITHUB_APP_CLIENT_ID, GITHUB_APP_INSTALLATION_ID, GITHUB_APP_PRIVATE_KEY_B64 - Returns WARN if any are missing (not FAIL - GitHub access is optional) - Non-blocking: Phantom boots without GitHub, fails lazily at first use
Add documentation for GitHub App authentication: - Environment variables table updated with GitHub App vars - Token rotation playbook (when to rotate, how to rotate) - Audit trail information - Security notes (never commit keys, use .env.local) Also update constitution principle count from 8 to 9 (workflow principle added in Phase 1+2).
4183a87 to
e44301e
Compare
Addresses three critical security vulnerabilities found in code review: 1. Token disclosure via stdout - Model could run `gh auth token` or `git -c alias.x=!env x` to print GH_TOKEN. Fixed by: - Adding validateGhSubcommand() to block gh auth/secret/config/ssh-key/gpg-key - Blocking git -c flag entirely (can execute arbitrary commands) 2. Private key exposure - runtime.ts passed ...process.env to SDK subprocess, exposing GITHUB_APP_PRIVATE_KEY_B64 to shell commands. Fixed by: - Creating buildAgentEnv() that strips secrets before passing to subprocess - Updating runtime.ts and judge-query.ts to use filtered env 3. Pipe deadlock - Sequential stdout/stderr reads could deadlock on large output. Fixed by: - Extracting drainProcessWithLimits() to shared utils/process.ts - Using concurrent Promise.all() drain with timeout and output caps - 2 minute timeout, 1MB output limit per stream Defense-in-depth: Added redactTokensFromOutput() to scan output for GitHub token patterns (ghs_*, ghp_*, github_pat_*) and replace with [REDACTED]. New tests: 70+ tests covering all security layers.
Review fixes: 1. Block git --config (space-separated form) - Added `arg === "--config"` to catch `git --config alias.x=!env x` - Previous check only caught `--config=` form 2. Split in-process-tools.ts to meet 300-line limit - Extracted GitHub exec logic to src/agent/gh-exec.ts (255 lines) - in-process-tools.ts now 128 lines - Re-exports from gh-exec.ts for backwards compatibility Added test for --config space-separated bypass vector.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GitHub App integration for
phantom_gh_execwith comprehensive security hardening addressing three critical vulnerabilities:gh auth token,gh secret, andgit -c/--configcommands that could print GH_TOKENbuildAgentEnv()to strip secrets (GITHUB_APP_PRIVATE_KEY_B64, SLACK_BOT_TOKEN, etc.) from SDK subprocess environmentdrainProcessWithLimits()with 2-minute timeout and 1MB output capDefense-in-depth layers
gh auth,gh secret,gh config,gh ssh-key,gh gpg-keygit -c,git --config(both=and space-separated forms)ghs_*,ghp_*,gho_*,ghu_*,github_pat_*tokens in stdout/stderrGITHUB_APP_PRIVATE_KEY_B64and other secrets excluded from subprocessKey files
src/agent/gh-exec.ts- GitHub exec logic with security validationsrc/agent/subprocess-env.ts-buildAgentEnv()for secret filteringsrc/agent/runtime.ts- Use filtered env for SDK subprocesssrc/utils/process.ts- ShareddrainProcessWithLimits()utilitysrc/integrations/github-app.ts- Token broker with cachingTest coverage
Test plan
gh auth tokenreturns blocked errorgit -c alias.x=!env xreturns blocked errorgit --config alias.x=!env xreturns blocked errorGITHUB_APP_PRIVATE_KEY_B64[REDACTED]