Skip to content

Fix top 5 priority issues: WS auth bypass, read-only assistant, init-timeout UX, idle disconnects#238

Merged
leonvanzyl merged 5 commits into
masterfrom
fix/top-5-priority-issues
Jul 16, 2026
Merged

Fix top 5 priority issues: WS auth bypass, read-only assistant, init-timeout UX, idle disconnects#238
leonvanzyl merged 5 commits into
masterfrom
fix/top-5-priority-issues

Conversation

@leonvanzyl

Copy link
Copy Markdown
Collaborator

Resolves the top 5 triaged issues by priority: #235 (P0), #233, #221, #215, #210.

#235 — Pre-auth RCE via terminal WebSocket (CWE-306 / CSWSH)

Starlette's HTTP-only localhost/CORS middleware never runs for websocket scopes, so all WS endpoints (including the PTY terminal) accepted cross-origin and remote connections unauthenticated. Added a pure-ASGI WebSocketOriginMiddleware (server/utils/ws_security.py, registered unconditionally in server/main.py) that rejects handshakes with close code 4403 before any route handler runs unless the Origin is a localhost variant (or, with AUTOFORGE_ALLOW_REMOTE=1, matches the Host header). Covers all five WS endpoints and any added later. Origin-less non-browser clients and HTTP traffic are unaffected, so the existing UI (prod :8888, Vite dev :5173 via proxy) keeps working. Includes new tests in test_ws_security.py.

#233 — Assistant implementing code instead of delegating

The "read-only" assistant relied on prompt text while running with permissions that skipped all checks. Now enforced at the tool level: disallowed_tools (Write/Edit/MultiEdit/NotebookEdit/Bash + coding-agent-only feature MCP tools) actually removes the tools from the model, plus a permissions.deny list in the generated settings as belt-and-suspenders, plus a strengthened system prompt directing users to create features for the coding agents. The same flaw existed in the expand-project chat and got the same hardening.

#221 — "Control request timeout: initialize" opening expand/assistant chat

Two-part fix: fail fast with a clear error in server/main.py and start.py when running Python < 3.11 (the reporter was on unsupported 3.10), and a shared format_client_init_error() helper (server/services/chat_constants.py) that translates the opaque SDK handshake timeout into actionable guidance (claude login, CLI reinstall, antivirus on Windows, CLAUDE_CODE_STREAM_CLOSE_TIMEOUT). All three chat sessions now surface that message over the WebSocket instead of a bare "Failed to initialize Claude".

#215 — UI constantly disconnecting after idle

Hardened ui/src/hooks/useWebSocket.ts: 20s application-level heartbeat with dead-connection detection (force-close + immediate exponential-backoff reconnect if no traffic for 90s instead of sitting stale), visibilitychange/online listeners to reconnect immediately when a backgrounded tab wakes (bypassing browser timer throttling), and fixes for zombie reconnects/duplicate sockets by clearing pending timers and detaching handlers before intentional closes. Server already answers {"type":"ping"} with pong, so no backend change was needed.

#210 — Crash on unknown rate_limit_event message type

Verified as already fixed on master (PR #211): every SDK message-stream consumer handles MessageParseError by logging and resuming (agent.py:82-136; the three chat sessions via safe_receive_response() in server/services/chat_constants.py:99-124), and check_rate_limit_error() short-circuits MessageParseError before the rate-limit regex. No changes needed — issue #210 can be closed once confirmed by the reporter.

Verification

  • ruff check . — pass
  • python test_security.py + test_security_integration.py — pass (169 tests)
  • pytest test_client.py test_rate_limit_utils.py test_dependency_resolver.py — pass
  • ui: npm run lint and npm run build — pass

An adversarial correctness/security review of the diff is finishing; any confirmed findings will be pushed as follow-up commits on this branch.

🤖 Generated with Claude Code

leonvanzyl and others added 5 commits April 19, 2026 13:06
Starlette's http middleware never runs for WebSocket scopes, so the
localhost guard did not protect any WS route and any web page could
hijack the terminal PTY socket (CWE-306). Adds a pure-ASGI
WebSocketOriginMiddleware that rejects handshakes from non-localhost
(or, in remote mode, non-matching-Host) origins with close code 4403
before the route handler runs, covering all five WS endpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The assistant and expand chat sessions only forbade code modification via
prompt text; with permission_mode=bypassPermissions, Write/Edit/Bash remained
fully callable. Add disallowed_tools (which actually removes tools from the
model) plus a permissions deny list in the generated settings, block coding-
agent-only feature MCP tools, and strengthen the assistant system prompt to
direct users to create features for the coding agents instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nd enforce Python 3.11+

Fail fast with a clear message in server/main.py and start.py when running
on Python < 3.11 (previously the unsupported interpreter only manifested as
an opaque SDK 'Control request timeout: initialize'). Add a shared
format_client_init_error() helper in chat_constants.py and use it in the
expand, assistant, and spec chat sessions so handshake timeouts yield
actionable guidance (auth, CLI install, antivirus, timeout env var) over
the WebSocket instead of a bare 'Failed to initialize Claude'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gered reconnect

The UI socket had a fire-and-forget ping with no dead-connection detection,
timer-only reconnects that browsers throttle in idle/background tabs, and a
cleanup path whose orphaned onclose could schedule zombie reconnects. The hook
now tracks last inbound message time, force-closes stale sockets (90s) from a
20s heartbeat, reconnects immediately on visibilitychange/online, and detaches
handlers on intentional close.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@leonvanzyl leonvanzyl merged commit 427c228 into master Jul 16, 2026
2 checks passed
@leonvanzyl leonvanzyl deleted the fix/top-5-priority-issues branch July 16, 2026 11:37
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.

2 participants