mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-07 14:06:42 +02:00
security(E3): gate GSTACK_SLUG on /welcome path traversal
The /welcome handler interpolates GSTACK_SLUG directly into the filesystem path used to locate the project-local welcome page. Without validation, a slug like "../../etc/passwd" would resolve to ~/.gstack/projects/../../etc/passwd/designs/welcome-page-20260331/finalized.html — classic path traversal. Not exploitable today: GSTACK_SLUG is set by the gstack CLI at daemon launch, and an attacker would already need local env-var access to poison it. But the gate is one regex (^[a-z0-9_-]+$), and a defense-in-depth pass costs us nothing when the cost of being wrong is arbitrary file read via /welcome. Fall back to the safe 'unknown' literal when the slug fails validation — same fallback the code already uses when GSTACK_SLUG is unset. No behavior change for legitimate slugs (they all match the regex). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1581,8 +1581,13 @@ async function start() {
|
||||
// Welcome page — served when GStack Browser launches in headed mode
|
||||
if (url.pathname === '/welcome') {
|
||||
const welcomePath = (() => {
|
||||
// Check project-local designs first, then global
|
||||
const slug = process.env.GSTACK_SLUG || 'unknown';
|
||||
// Gate GSTACK_SLUG on a strict regex BEFORE interpolating it into
|
||||
// the filesystem path. Without this, a slug like "../../etc/passwd"
|
||||
// would resolve to ~/.gstack/projects/../../etc/passwd/... — path
|
||||
// traversal. Not exploitable today (attacker needs local env-var
|
||||
// access), but the gate is one regex and buys us defense-in-depth.
|
||||
const rawSlug = process.env.GSTACK_SLUG || 'unknown';
|
||||
const slug = /^[a-z0-9_-]+$/.test(rawSlug) ? rawSlug : 'unknown';
|
||||
const homeDir = process.env.HOME || process.env.USERPROFILE || '/tmp';
|
||||
const projectWelcome = `${homeDir}/.gstack/projects/${slug}/designs/welcome-page-20260331/finalized.html`;
|
||||
if (fs.existsSync(projectWelcome)) return projectWelcome;
|
||||
|
||||
Reference in New Issue
Block a user