[Bug]: WebSocket verifyClient allows unauthenticated local connections via missing Origin header
- Dominant language
- JavaScript
- Stars
- 29.3k
- Forks
- 2.9k
- Avg merge
- 15h 36m
- Merged PRs (30d)
- 70
Description
Hey! Following up from #268 — the CSRF fix was solid, but I noticed the WebSocket endpoint still has a gap.
The `verifyClient` check does this:
```js
return !origin || origin.startsWith('chrome-extension://');
```
The problem is the `!origin` part — if there's no Origin header at all, the connection is allowed through. Node.js WebSocket clients don't send Origin by default, so any script on the machine can connect to `ws://127.0.0.1:19825/ext` and impersonate the extension:
```js
const ws = new WebSocket('ws://127.0.0.1:19825/ext');
// connects successfully, full access, no auth needed
```
Same goes for the HTTP side — `X-OpenCLI: 1` blocks browsers nicely, but it's a hardcoded value in the source code, not a secret. Any local process that reads the repo knows to add it.
I think the cleanest fix would be generating a random token on first run (stored at `~/.opencli/token`), and requiring it in the WebSocket handshake and HTTP requests. The extension and CLI can both read the file. Everything else gets rejected.
This matters more now that AI agents (Claude Code, Cursor, etc.) are running locally alongside tools like OpenCLI — the attack surface for local process impersonation is growing.
Contributor guide
Research direction
Start by locating the WebSocket verifyClient check for ws://127.0.0.1:19825/ext and the HTTP handling that checks X-OpenCLI: 1. Review how the extension and CLI currently connect. Done means unauthenticated local WebSocket and HTTP requests are rejected while the extension and CLI authenticate with a generated token.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- authentication, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100