Skip to content

Thread-Unsafe Global _workspace_path_override Race #43

@bradjin8

Description

@bradjin8

Repository: cppa-cursor-browser
Assignee: Brad @bradjin8
Severity: High

Problem

The module-level global _workspace_path_override in utils/workspace_path.py is the project's only shared mutable state. It is written by the POST /api/set-workspace route handler and read by every subsequent request's call to resolve_workspace_path(). No lock, no atomic operation, and no threading check guards the mutation. Under any threaded WSGI deployment (gunicorn with --threads, waitress, etc.), concurrent requests to set-workspace and any data-reading endpoint race on server-wide state, potentially serving one user's workspace data to another user's request.

Acceptance Criteria

  • _workspace_path_override is protected by a threading.Lock (or equivalent synchronization primitive) for both reads and writes
  • Alternatively: refactor to eliminate the mutable global entirely (e.g., pass workspace path via Flask g, session, or request context)
  • Add a unit test that exercises concurrent set-workspace + resolve_workspace_path calls under threading to verify no data races
  • If the global-lock approach is chosen, document the locking contract in a code comment on _workspace_path_override

Implementation Notes

The cleanest fix is to move workspace path into Flask's request-scoped g object or session, eliminating the shared mutable global entirely. This would make the application inherently safe under threaded deployment without any locking overhead. If that refactoring is too invasive for this sprint, a threading.Lock wrapping the read/write of _workspace_path_override is the minimum viable fix. Either way, the race is currently latent (single-threaded Werkzeug default) but becomes exploitable the moment anyone deploys with --threads. The fix here also unblocks item 7 (threading/deployment documentation) — you can't document safety guarantees until the code actually provides them.

References

  • Eval finding: test 13
  • Cluster: workspace-path-race-condition
  • Related files: utils/workspace_path.py, api/workspaces.py (the set-workspace route handler)
  • Compounds: COMPOUND-B (race condition + missing documentation), COMPOUND-E (undocumented API + race condition)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No fields configured for Task.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions