Skip to content

fix: path traversal in design serve /api/reload — arbitrary file read#752

Open
Gonzih wants to merge 1 commit intogarrytan:mainfrom
Gonzih:fix/design-serve-path-traversal
Open

fix: path traversal in design serve /api/reload — arbitrary file read#752
Gonzih wants to merge 1 commit intogarrytan:mainfrom
Gonzih:fix/design-serve-path-traversal

Conversation

@Gonzih
Copy link
Copy Markdown

@Gonzih Gonzih commented Apr 1, 2026

The Bug

`POST /api/reload` in `design/src/serve.ts` accepts a JSON body with an arbitrary `html` path and reads it with no validation:

```typescript
const newHtmlPath = body.html;
if (!newHtmlPath || !fs.existsSync(newHtmlPath)) { ... } // existence check only
htmlContent = fs.readFileSync(newHtmlPath, "utf-8"); // reads anything
```

The design server binds to localhost, but the Chrome extension (or any local process) can POST to it. Attack:

```
POST /api/reload {"html": "/etc/passwd"}
GET / → returns contents of /etc/passwd
```

Issue #672.

Fix

Validate that the reload path resolves within the same directory as the original HTML file. Paths outside are rejected with 403. The agent only ever reloads variant files in the same output directory — legitimate use is unaffected.


sent from mStack

POST /api/reload accepts a { html: "/path/to/file.html" } body and
reads that file with fs.readFileSync() without path validation.
Any path the caller controls gets read and served via GET /.

Attack: POST /api/reload {"html": "/etc/passwd"}
→ GET / returns the contents of /etc/passwd

Fix: validate that the reload path resolves within the same directory
as the original HTML file passed to serve(). Paths outside that
directory are rejected with 403. Uses path.resolve() to canonicalize
before comparison.

Closes garrytan#672
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