Files
clawhub/vercel.json
Patrick ErichsenandClaude Opus 4.7 4fe275eb50 fix(security): enable safe SVG handling so shields.io badges render
vercel.json currently allow-lists SVG-only hosts (img.shields.io,
shields.io, badgen.net, flat.badgen.net) while dangerouslyAllowSVG:
false rejects every SVG source. Those two settings are incompatible,
and every badge in every README on production is returning 400
INVALID_IMAGE_OPTIMIZE_REQUEST (e.g. the license badge on
/plugins/@opik/opik-openclaw).

Switch to the pattern Vercel documents for safely serving SVGs in
their NEXTJS_SAFE_SVG_IMAGES conformance rule:

- dangerouslyAllowSVG: true  — lets the optimizer accept SVG inputs
- contentDispositionType: attachment  — forces download instead of
  inline document rendering if someone navigates directly to the
  /_vercel/image URL (the only context where SVG scripts would run)
- contentSecurityPolicy: script-src 'none'; sandbox;  — blocks script
  execution in the response

Defense in depth: browsers already sandbox SVGs loaded through <img>
so scripts don't run there anyway; the CSP + attachment header cover
the edge case of someone opening the optimizer URL directly. Net
security is equivalent to rejecting SVGs, but badges actually render.

Docs: https://vercel.com/docs/conformance/rules/NEXTJS_SAFE_SVG_IMAGES

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 22:50:43 -07:00

61 lines
1.9 KiB
JSON

{
"redirects": [
{
"source": "/",
"has": [
{
"type": "header",
"key": "host",
"value": "mirror-cn.clawhub.com"
}
],
"destination": "https://cn.clawhub-mirror.com/",
"statusCode": 302
},
{
"source": "/:path*",
"has": [
{
"type": "header",
"key": "host",
"value": "mirror-cn.clawhub.com"
}
],
"destination": "https://cn.clawhub-mirror.com/:path*",
"statusCode": 302
}
],
"rewrites": [
{
"source": "/api/:path*",
"destination": "https://wry-manatee-359.convex.site/api/:path*"
}
],
"images": {
"sizes": [256, 640, 1024, 1920],
"formats": ["image/webp"],
"minimumCacheTTL": 86400,
"dangerouslyAllowSVG": true,
"contentDispositionType": "attachment",
"contentSecurityPolicy": "default-src 'self'; script-src 'none'; sandbox;",
"remotePatterns": [
{ "protocol": "https", "hostname": "raw.githubusercontent.com" },
{ "protocol": "https", "hostname": "user-images.githubusercontent.com" },
{ "protocol": "https", "hostname": "avatars.githubusercontent.com" },
{ "protocol": "https", "hostname": "camo.githubusercontent.com" },
{ "protocol": "https", "hostname": "github.com" },
{ "protocol": "https", "hostname": "raw.github.com" },
{ "protocol": "https", "hostname": "img.shields.io" },
{ "protocol": "https", "hostname": "shields.io" },
{ "protocol": "https", "hostname": "cdn.jsdelivr.net" },
{ "protocol": "https", "hostname": "i.imgur.com" },
{ "protocol": "https", "hostname": "codecov.io" },
{ "protocol": "https", "hostname": "coveralls.io" },
{ "protocol": "https", "hostname": "codefactor.io" },
{ "protocol": "https", "hostname": "badgen.net" },
{ "protocol": "https", "hostname": "flat.badgen.net" },
{ "protocol": "https", "hostname": "gitlab.com" }
]
}
}