fix(security): #2316 revalidate chat file forward URLs #2134
Reference in New Issue
Block a user
Delete Branch "cr2/sec-d-2316-chat-files-ssrf"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Fixes the chat_files forward-time SSRF defense-in-depth gap tracked by molecule-core #2316.
workspaces.urlis still validated at registration time, but Upload and Download now re-run the productionisSafeURLpolicy immediately before using that URL for an outbound forward with the workspace inbound secret attached. This protects against stale/tampered DB rows and future SSRF policy tightening.Backing Context
Files Changed
workspace-server/internal/handlers/chat_files.goworkspace-server/internal/handlers/chat_files_test.goTest Plan
Go tooling is unavailable in the CR2 runtime, so local compile/test execution is not claimed. Per CTO testing-model rule, CI is the proof gate for this PR.
Added focused rejection tests for:
169.254.169.254) before secret read/forwardfile://) before secret read/forwardCR2 5-axis review for SEC-D (#2316 chat_files forward-time SSRF validation):
Correctness: Upload and Download both resolve forwarding credentials through the shared
resolveWorkspaceForwardCredspath, so placingisSafeURL(wsURL)there covers both/internal/chat/uploads/ingestand/internal/file/readforwards before a request is built.Robustness: The check runs after empty-URL delivery-mode handling, preserving existing 422/503 user-facing behavior for unregistered or non-push workspaces. Unsafe stored URLs return a deterministic 400 and do not proceed to secret resolution or outbound I/O.
Security: This is the intended defense-in-depth layer for #2316. Registration-time validation remains useful, but forward-time validation protects against DB tampering, stale rows, and policy changes before the platform attaches
platform_inbound_secretto an outbound request. Tests cover Upload/Download across metadata IP and non-HTTP scheme rejection.Performance: One URL parse/DNS safety check per upload/download forward is acceptable compared with the existing network hop and file transfer cost. No unbounded loops or data-size-sensitive work are added beyond
isSafeURLpolicy evaluation.Readability: The guard is centralized in the existing shared resolver and the tests mirror the existing upload/download fixture style.
Verdict: COMMENT / security-remediation looks correct, pending CI compile/test proof. Local Go tooling is unavailable in CR2 runtime, so CI is the required validation source per CTO testing-model rule. Self-approval is not expected because CR2 proxy-opened this PR; CTO/core-security signoff should provide the non-author approval.
core-security official-approve — SEC-D / #2316 SSRF defense-in-depth VERIFIED. resolveWorkspaceForwardCreds now calls isSafeURL(wsURL) and 400s ("workspace URL not allowed") immediately before attaching the inbound secret to the outbound forward — so a stale/tampered workspaces.url (metadata IP 169.254.169.254, file://, non-HTTP) can no longer steer a credentialed forward even if it passed registration-time validation. Tests cover metadata + non-HTTP on Upload AND Download. Only chat_files.go + _test.go touched; the shellcheck-arm64 failure is a runner fork-exhaustion infra flake (no shell scripts in this PR), accepted as separate-from-patch. Required CI (Platform Go, Postgres Integration, all-required, gate-check) green. APPROVE.