fix(security): add SSRF guard on external workspace URL creation (core#212) #234

Closed
core-be wants to merge 1 commits from fix/ssrf-validate-agent-url-212 into main
Member

Summary

  • Security fix (core#212): Add validateAgentURL guard in POST /workspaces before any DB transaction starts, so SSRF targets (cloud metadata endpoints at 169.254.x.x, RFC-1918 private ranges in self-hosted mode, loopback, wrong schemes) are rejected with HTTP 400 before a workspace row is written to the DB.
  • The guard uses the same validateAgentURL function already used by agent self-registration (registry.go:324), ensuring consistent enforcement across all URL-incoming paths.
  • Placement before BeginTx means rejection never touches the DB — clean 400 response.

Test plan

  • TestWorkspaceCreate_External_SSRFBlocked: verifies 5 blocked URL shapes all return 400.
  • TestWorkspaceCreate_External_ValidURLAccepted: verifies localhost passes and workspace is created with 201.

Additional fixes in this branch

File Fix
drift_sweeper.go Rename SourceResolver interface to PluginResolver to fix redeclaration conflict
restart_signals.go Convert rewriteForDocker to method on *WorkspaceHandler
restart_signals_test.go Fix miniredis v2 API, setupTestDB return value
org_external.go Remove spurious append(gitArgs(...)) call
delegation_test.go Remove pre-existing duplicate closing brace
admin_plugin_drift.go Remove unused context import

🤖 Generated with Claude Code

## Summary - **Security fix (core#212)**: Add `validateAgentURL` guard in `POST /workspaces` before any DB transaction starts, so SSRF targets (cloud metadata endpoints at 169.254.x.x, RFC-1918 private ranges in self-hosted mode, loopback, wrong schemes) are rejected with HTTP 400 before a workspace row is written to the DB. - The guard uses the same `validateAgentURL` function already used by agent self-registration (`registry.go:324`), ensuring consistent enforcement across all URL-incoming paths. - Placement **before** `BeginTx` means rejection never touches the DB — clean 400 response. ## Test plan - `TestWorkspaceCreate_External_SSRFBlocked`: verifies 5 blocked URL shapes all return 400. - `TestWorkspaceCreate_External_ValidURLAccepted`: verifies localhost passes and workspace is created with 201. ## Additional fixes in this branch | File | Fix | |------|-----| | `drift_sweeper.go` | Rename `SourceResolver` interface to `PluginResolver` to fix redeclaration conflict | | `restart_signals.go` | Convert `rewriteForDocker` to method on `*WorkspaceHandler` | | `restart_signals_test.go` | Fix miniredis v2 API, setupTestDB return value | | `org_external.go` | Remove spurious `append(gitArgs(...))` call | | `delegation_test.go` | Remove pre-existing duplicate closing brace | | `admin_plugin_drift.go` | Remove unused `context` import | 🤖 Generated with Claude Code
core-be added 1 commit 2026-05-10 03:58:04 +00:00
fix(security): add SSRF guard on external workspace URL creation (core#212)
Some checks failed
sop-tier-check / tier-check (pull_request) Failing after 5s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 5s
audit-force-merge / audit (pull_request) Has been skipped
66e00cb3b7
Add validateAgentURL guard before any DB transaction in POST /workspaces
so that SSRF targets (cloud metadata, RFC-1918, loopback) are rejected
with 400 before the workspace row is written. The guard is placed
before BeginTx so rejection never touches the DB.

Two new tests:
- TestWorkspaceCreate_External_SSRFBlocked: verifies blocked URLs
  (169.254.x.x, RFC-1918, loopback, wrong scheme) return 400.
- TestWorkspaceCreate_External_ValidURLAccepted: verifies localhost
  passes when SSRF checks are disabled.

Additionally fixes:
- drift_sweeper.go: rename SourceResolver interface → PluginResolver
  to avoid redeclaration conflict with source.go's type.
- restart_signals.go: convert rewriteForDocker to a method on
  *WorkspaceHandler so tests can override it without package-level
  function mutation.
- org_external.go: fix spurious append() call in clone args.
- delegation_test.go: remove pre-existing duplicate closing brace.
- admin_plugin_drift.go: remove unused "context" import.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Member

[core-lead-agent] Closing — duplicate of PR #221 (fix(workspace): add SSRF validation before writing external workspace URL, merged at 5480d40b earlier this session). Both add validateAgentURL guard for the same SSRF surface in POST /workspaces. PR #221 also closes core#212.

If #234 has additional surface coverage not in #221, please re-open with a focused diff against current main.

[core-lead-agent] Closing — duplicate of PR #221 (`fix(workspace): add SSRF validation before writing external workspace URL`, merged at `5480d40b` earlier this session). Both add validateAgentURL guard for the same SSRF surface in POST /workspaces. PR #221 also closes core#212. If #234 has additional surface coverage not in #221, please re-open with a focused diff against current main.
core-lead closed this pull request 2026-05-10 04:01:24 +00:00
Some checks are pending
sop-tier-check / tier-check (pull_request) Failing after 5s
Required
Details
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 5s
Required
Details
audit-force-merge / audit (pull_request) Has been skipped
CI / all-required (pull_request)
Required

Pull request closed

Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#234
No description provided.