Background
gstack is an open-source toolkit released by Y Combinator president Garry Tan on March 12, 2026. It packages Claude Code — Anthropic's CLI-based AI coding agent — into a set of slash commands that automate plan reviews, code reviews, QA testing, shipping, and browser-based dogfooding. A persistent headless Chromium daemon provides the browser layer.
The README describes gstack as an opinionated, personal workflow system: “ten opinionated workflow skills” that turn “one generic assistant into a team of specialists.” It is explicitly framed as tooling built for one person's workflow, then open-sourced for others to adopt or fork.
This review examines the security boundaries of those markdown files and the server code that backs them. We found two server-level security issues in the headless browser daemon. The rest of this review is design analysis — how the tool handles trust boundaries between human intent and AI agent action, and what that means for users who adopt it without reading 600 lines of prompt instructions.
Methodology
The gstack repository (github.com/garrytan/gstack, version 0.4.4, commit c86faa7) was cloned and all files were read in full. The analysis covered every SKILL.md prompt template, the headless browser server source (browse/src/), the review checklist, the Greptile integration, the upgrade mechanism, supporting configuration files, tests, and project documentation (README, ARCHITECTURE.md, CONTRIBUTING.md, CHANGELOG.md).
This is a static review of prompt design, architectural decisions, and trust boundaries — not a live exploitation exercise. No running instance of gstack was attacked. Findings are based on what the prompts instruct the AI agent to do and what the server code permits.
Security Findings
1. Cookie picker endpoint bypasses authentication
CWE-306 / Missing Authentication for Critical FunctionThe headless browser server authenticates commands using a per-session Bearer token generated at startup and stored in a state file. However, the cookie picker routes bypass this authentication entirely:
browse/src/server.ts — line 306
// Cookie picker routes — no auth required (localhost-only)
if (url.pathname.startsWith('/cookie-picker')) {
return handleCookiePickerRoute(url, req, browserManager);
}This check occurs before the Bearer token validation at line 326. The route handler confirms this is intentional, with a comment in cookie-picker-routes.ts reading “Routes (no auth — localhost-only, accepted risk).”
The unauthenticated surface includes six endpoints: serving the picker UI, listing installed browsers, listing cookie domains and counts for a browser, importing decrypted cookies into Playwright, removing cookies for domains, and listing currently imported domains. Any local process on the same machine — a malicious npm package or a compromised dev tool — can hit these endpoints without credentials. Cross-origin browser access is limited by a CORS policy pinned to http://127.0.0.1:{port}, so browser-tab exploitation would require a same-origin context.
The unauthenticated /health endpoint further assists discovery by returning the server's current URL, tab count, and uptime.
Impact
Any local process can enumerate installed browsers, discover which cookie domains are available, import decrypted cookies into the headless session, or remove existing imported cookies. This does not by itself grant full browser control (which requires the Bearer token), but it allows a local attacker to manipulate the authentication state of the headless session.
Mitigation
Apply Bearer token authentication to all routes including the cookie picker. The existing auth mechanism is already in place — move the cookie picker route handler below the auth check.
2. Project-local bearer token file allows same-user browser takeover
CWE-522 / Insufficiently Protected CredentialsThe browse server writes a state file to .gstack/browse.json within the project directory containing the Bearer token that grants full control of the headless browser:
State file contents (browse/src/server.ts — line 343)
{
"pid": 12345,
"port": 34567,
"token": "a1b2c3d4-...", // Bearer token — full browser control
"startedAt": "2026-03-16T...",
"serverPath": "/path/to/server.ts",
"binaryVersion": "abc123"
}The file is written with mode 0o600 (owner-only). gstack also auto-appends .gstack/ to the project's .gitignore in browse/src/config.ts, so accidental git commits are mitigated. However, any process running as the same user can read this file from its predictable path.
The token grants full control of the headless browser session: navigation to any URL, JavaScript execution via js and eval commands, cookie reading, screenshot capture, form interaction, and file upload. The eval command enforces server-side path restrictions (in read-commands.ts) limiting file execution to /tmp and the current working directory. The js command executes arbitrary expressions directly in the browser context with no path restriction.
When the session contains imported real-browser cookies (the intended workflow via /setup-browser-cookies), a compromised token gives the attacker authenticated access to every domain the user has imported cookies for.
Impact
A same-user local process (malicious npm package or compromised dependency) that reads the state file gains full control of a headless browser session that may carry real-browser cookies. This is functionally equivalent to session hijacking across every imported domain.
Mitigation
Store the state file in a user-scoped directory (e.g., ~/.gstack/browse-<project-hash>.json) rather than the project directory. Consider using Unix domain sockets instead of TCP with a token file, which eliminates the credential storage problem.
Trust Boundary Analysis
The following are not vulnerabilities. They are design decisions that create novel trust boundaries between human intent and AI agent action. We document them because they matter for users evaluating the tool.
Localhost trust assumption
gstack's headless browser server treats localhost as a trusted zone. This is stated explicitly in cookie-picker-routes.ts: “no auth — localhost-only, accepted risk.” For many development tools this is reasonable. It is weaker than it appears in environments where untrusted code runs locally — npm postinstall scripts, VS Code extensions, and any process under the same UID. Finding 1 is a direct consequence of this assumption.
Greptile comment ingestion
The /review and /ship skills fetch Greptile bot comments from the GitHub API and feed them into Claude's context for classification. The entire comment body is ingested as trusted input. A compromised Greptile service could craft a comment body containing prompt injection payloads that influence how the AI classifies review findings.
The blast radius is limited: most consequential actions (applying fixes, acknowledging issues) are gated by AskUserQuestion prompts that require explicit user choice. The classification step itself (VALID vs FALSE POSITIVE vs SUPPRESSED) runs without human intervention, but the actions that follow it do not.
Autonomous commit and push
The /qa skill autonomously finds bugs by browsing a website, edits source code, and commits — up to 50 times per session with no human review gate. The /ship skill auto-generates CHANGELOG entries, splits changes into commits, pushes to remote, and creates a pull request. The prompt explicitly states: “Do NOT ask for confirmation at any step.”
These are intentional behaviors, not bugs. The user invokes them deliberately. But they represent a gap between what the human authorized (a single slash command) and what the AI agent executes (a multi-step workflow involving irreversible actions like git push and PR creation). Users who have not read the 600-line skill prompts may not understand the scope of what they are authorizing.
Design Review
The following are opinions about gstack's design. They are not security findings. We include them because they affect the practical value of the tool for users adopting it outside its original context.
Review checklist is Rails-centric
The review checklist that backs /review and /ship has four CRITICAL categories. Two — SQL & Data Safety and Race Conditions & Concurrency — contain heuristics specific to Ruby on Rails (sanitize_sql_array, update_column, find_or_create_by, .html_safe). The other two — LLM Output Trust Boundary and Enum & Value Completeness — are generic and apply across stacks. The INFORMATIONAL pass also includes generic categories (Crypto & Entropy, Time Window Safety, Type Coercion at Boundaries).
The README is transparent that gstack is opinionated. The issue is not that the checklist is Rails-focused — it is that the review output does not indicate which categories applied. A user running /review on a Go service sees “No issues found” without knowing that the SQL injection, XSS, and race condition heuristics did not apply to their code.
Review suppressions
The checklist pre-emptively silences certain finding categories, including “Regex doesn't handle edge case X when the input is constrained and X never occurs in practice.” Most suppressions are sensible noise reduction. This particular one embodies the assumption attackers target — that constrained input will stay constrained.
Vendored upgrade path
The vendored-install upgrade path replaces the entire gstack directory and deletes the backup (rm -rf "$INSTALL_DIR.bak"). The git-install path uses git reset --hard but stashes tracked changes first and preserves untracked files. If auto-upgrade is enabled, the vendored path can destroy customizations without explicit user action.
Prompt bloat
Every skill includes an identical preamble (~330 tokens) with upgrade checks, formatting rules, contributor mode instructions, and base branch detection. The preamble is generated from a shared template but duplicated in full into each SKILL.md. The /plan-ceo-review skill is 573 lines with 10 review sections, each requiring the AI to stop and ask the user a question. Longer prompts mean more competition for the model's attention — the most important instructions (security checklist categories) share context with upgrade checks and formatting boilerplate.
Disclosure
This review was performed on the publicly available gstack repository (github.com/garrytan/gstack, version 0.4.4, commit c86faa7). All findings are based on static analysis of prompt files, server source code, tests, and project documentation. No running instance of gstack was attacked or accessed.
gstack is open source under the MIT license. Several design decisions noted in this review (session tracking, contributor mode, the “opinionated” framing) are documented in the project's ARCHITECTURE.md, CONTRIBUTING.md, and README. This review aims to surface security considerations for users evaluating the tool, not to characterize documented features as undisclosed.