Skip to content

fix(security): close IPv6 SSRF gap in validateAgentURL (C6) - #112

Closed
HongmingWang-Rabbit wants to merge 1 commit into
mainfrom
fix/ssrf-ipv6-blocklist
Closed

fix(security): close IPv6 SSRF gap in validateAgentURL (C6)#112
HongmingWang-Rabbit wants to merge 1 commit into
mainfrom
fix/ssrf-ipv6-blocklist

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

  • Root cause: validateAgentURL in registry.go only blocked 169.254.0.0/16. Go's (*IPNet).Contains() does not match pure IPv6 addresses against IPv4 CIDRs, leaving three IPv6 ranges fully open as SSRF vectors.
  • Gap confirmed by QA: http://[::1]:8080, http://[fe80::1]:8080, and http://[fd00::1]:8080 all passed through without error.
  • Fix: Restructured the single-CIDR check into a blockedRanges loop and added three IPv6 entries:
    • fe80::/10 — IPv6 link-local (same threat class as 169.254.0.0/16; cloud metadata analogue)
    • ::1/128 — IPv6 loopback
    • fc00::/7 — IPv6 ULA (RFC-4193 private)
  • IPv4-mapped IPv6 (::ffff:169.254.169.254) requires no extra range: Go normalises these to IPv4 via To4() before Contains() runs, so they're already caught by the 169.254.0.0/16 entry. Documented in both code comment and a test case.
  • No allowlist changes: 127.0.0.1 and RFC-1918 ranges remain permitted (Docker networking requirement).

Test plan

  • go test -race -run TestValidateAgentURL ./platform/internal/handlers/ — 4 new cases added: [::1], [fe80::1], [fd00::1], [::ffff:169.254.169.254] all expect wantErr: true
  • Existing valid-URL cases (172.18.0.5, 127.0.0.1, 10.x, 192.168.x) remain wantErr: false
  • Full go test -race ./... in platform/
  • CI platform-build gate

🤖 Generated with Claude Code

PR #94 blocked 169.254.0.0/16 but left IPv6 equivalents fully open.
Go's (*IPNet).Contains() does not match pure IPv6 addresses against IPv4
CIDRs, so ::1, fe80::*, and fc00::/7 all bypassed the check.

Add three explicit IPv6 entries to blockedRanges:
  - fe80::/10  (IPv6 link-local — cloud metadata analogue)
  - ::1/128    (IPv6 loopback)
  - fc00::/7   (IPv6 ULA — RFC-4193 private)

IPv4-mapped IPv6 (::ffff:169.254.x.x) is already safe: Go normalises
these to IPv4 via To4() before Contains() runs.

Tests: four new cases in TestValidateAgentURL covering all three blocked
IPv6 ranges plus the IPv4-mapped IPv6 auto-normalisation path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor Author

Superseded by #119 (cherry-picked onto a clean base from main). IPv6 SSRF fix (e4e6634) is included in #119 with the correction that the IPv4 loopback and RFC-1918 blocks are preserved — this branch had inadvertently removed them.

HongmingWang-Rabbit added a commit that referenced this pull request Apr 15, 2026
fix(security+scheduler): IPv6 SSRF gap + scheduler unit tests [supersedes #111, #112]
@HongmingWang-Rabbit
HongmingWang-Rabbit deleted the fix/ssrf-ipv6-blocklist branch April 16, 2026 12:33
molecule-ai Bot pushed a commit that referenced this pull request Apr 20, 2026
…owlist

Fixes audit #125 findings for CWE-639:

1. admin_test_token.go — CRITICAL IDOR (finding #112)
   When ADMIN_TOKEN is set in production, require it explicitly on
   GET /admin/workspaces/:id/test-token. The original gap: AdminAuth
   accepted any valid org-scoped token, letting an Org A token holder
   mint workspace bearer tokens for ANY workspace UUID they could enumerate.
   Now requires ADMIN_TOKEN when it's configured; MOLECULE_ENV!=production
   path still requires a valid bearer (any org token works for local dev).

2. org_plugin_allowlist.go — HIGH IDOR (finding #112)
   GET and PUT /orgs/:id/plugins/allowlist: add requireOrgOwnership()
   check after org existence verification. Org-token holders can only
   read/write their own org's allowlist. Session and ADMIN_TOKEN callers
   bypass the check (they have platform-wide access via the session
   cookie path, not org tokens).

Closes: #112 (CWE-639 IDOR — tenant config access)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
molecule-ai Bot pushed a commit that referenced this pull request Apr 21, 2026
fix(security+scheduler): IPv6 SSRF gap + scheduler unit tests [supersedes #111, #112]
molecule-ai Bot pushed a commit that referenced this pull request Apr 21, 2026
…owlist

Fixes audit #125 findings for CWE-639:

1. admin_test_token.go — CRITICAL IDOR (finding #112)
   When ADMIN_TOKEN is set in production, require it explicitly on
   GET /admin/workspaces/:id/test-token. The original gap: AdminAuth
   accepted any valid org-scoped token, letting an Org A token holder
   mint workspace bearer tokens for ANY workspace UUID they could enumerate.
   Now requires ADMIN_TOKEN when it's configured; MOLECULE_ENV!=production
   path still requires a valid bearer (any org token works for local dev).

2. org_plugin_allowlist.go — HIGH IDOR (finding #112)
   GET and PUT /orgs/:id/plugins/allowlist: add requireOrgOwnership()
   check after org existence verification. Org-token holders can only
   read/write their own org's allowlist. Session and ADMIN_TOKEN callers
   bypass the check (they have platform-wide access via the session
   cookie path, not org tokens).

Closes: #112 (CWE-639 IDOR — tenant config access)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

1 participant