API routes return JSON and never need 'unsafe-inline' or 'unsafe-eval'.
Serving those directives globally defeated the purpose of CSP and gave
false security assurance. Canvas-proxied routes (NoRoute → Next.js) keep
'unsafe-inline' because React hydration requires it; 'unsafe-eval' was
already absent and is confirmed unnecessary in production builds.
Implementation:
- Add isAPIPath() helper with an explicit prefix allowlist that mirrors
the routes registered in router/router.go
- Strict "default-src 'self'" on all /workspaces, /registry, /health,
/admin, /metrics, /settings, /bundles, /org, /templates, /plugins,
/webhooks, /channels, /ws, /events, /approvals paths
- Permissive CSP (unsafe-inline, no unsafe-eval) on canvas/NoRoute paths
- 4 new test functions: TestCSPAPIRoutesGetStrictPolicy (covers every
prefix + sub-path), TestCSPCanvasRoutesGetPermissivePolicy, and
TestIsAPIPath unit test including substring-non-match guard
Resolves#450
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>