fix(security): validate UUID in GET /workspaces/:id — 500→400 (#687) - #699
Closed
molecule-ai[bot] wants to merge 1 commit into
Closed
fix(security): validate UUID in GET /workspaces/:id — 500→400 (#687)#699molecule-ai[bot] wants to merge 1 commit into
molecule-ai[bot] wants to merge 1 commit into
Conversation
Double-percent-encoded path traversal strings (e.g. ..%252f..%252fetc%252fpasswd) decode to non-UUID values that bypass Gin's path normalization and reach the DB handler. PostgreSQL's UUID type parser rejects the invalid string with an internal error that previously propagated as HTTP 500, leaking that a database is involved. Fix: call uuid.Parse() at the top of Get() before any DB access. Invalid UUIDs now return 400 Bad Request. The open-router GET /workspaces/:id is the primary attack surface (no WorkspaceAuth in the path); WorkspaceAuth-gated routes already surface 401 because ValidateToken() fails on the malformed workspace_id. Test updates: existing TestWorkspaceGet_* tests used non-UUID IDs (ws-get-1, ws-nonexistent, etc.) — updated to valid UUID-format strings so they still reach the DB query path. New TestWorkspaceGet_InvalidUUID_Returns400 verifies the fix across path-traversal strings, legacy workspace IDs, and empty input. Closes #687 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Finding (#687):
GET /workspaces/:idis on the open router with no authentication. Double-percent-encoded path traversal strings (e.g...%252f..%252fetc%252fpasswd) decode to..%2f..%2fetc%2fpasswdafter one URL-decode pass. Gin's path normalisation doesn't catch this, so the raw string reaches the handler and gets passed to PostgreSQL as a UUID parameter. PostgreSQL's type system rejects it, and the error propagated as HTTP 500 — leaking that a database is involved and providing a side-channel confirmation that the UUID parser was reached.Expected: HTTP 400 for any non-UUID
:id.Fix
WorkspaceAuth-gated routes (most/workspaces/:id/*paths) already return 401 for non-UUID IDs becauseValidateToken()fails whenworkspace_idis not a UUID — those routes do NOT return 500. The openGET /workspaces/:idis the primary attack surface.Test changes
Existing
TestWorkspaceGet_*tests used non-UUID IDs (ws-get-1,ws-nonexistent,ws-dberr,ws-fin-1) — updated to valid UUID-format strings so they still exercise the DB query path. New test:TestWorkspaceGet_InvalidUUID_Returns400— verifies 400 for path traversal strings, legacyws-*IDs, and empty string; confirms no DB calls are made.Test plan
go build ./...— clean compilego test ./internal/handlers/... -run TestWorkspaceGet— all 5 tests passgo test ./...passescurl -s http://localhost:8080/workspaces/..%252f..%252fetc%252fpasswd→ 400curl -s http://localhost:8080/workspaces/not-a-uuid→ 400curl -s http://localhost:8080/workspaces/<valid-uuid>→ 200 or 404 (no 500)Closes #687
🤖 Generated with Claude Code