Surfaced during the supply-chain hardening audit in #68.
Location: src/components/MDXRenderer.tsx:13
Issue: The component uses new Function(code) to instantiate the velite-emitted MDX. The next.config.mjs CSP allows 'unsafe-inline' for script-src but not 'unsafe-eval' — which is the right posture if and only if MDXRenderer runs exclusively on the server.
The next.config.mjs comment claims this is server-only:
MDXRenderer compiles velite-emitted JSX via new Function(code), but it's a server component — the eval happens at build/SSR time on the server, so the browser never sees the dynamic code and CSP doesn't need 'unsafe-eval'.
…but the component file itself has no "use server" directive or any other build-time assertion that enforces this. If someone imports MDXRenderer from a client component (knowingly or accidentally — the import path doesn't make the constraint obvious), the eval moves to the browser. CSP would block it (which is itself defense-in-depth), but the error would surface as a runtime failure in the catch block, not at build time.
Proposed fix: make the invariant explicit. Two complementary options:
- Add
"use server" (or import "server-only") at the top of MDXRenderer.tsx so the bundler errors at build time if it gets pulled into a client bundle.
- Add a build-time grep / lint rule in CI or
velite.config.ts that fails if MDXRenderer is imported from a file with "use client".
Either alone is sufficient; both is belt-and-braces.
Surfaced during the supply-chain hardening audit in #68.
Location: src/components/MDXRenderer.tsx:13
Issue: The component uses
new Function(code)to instantiate the velite-emitted MDX. Thenext.config.mjsCSP allows'unsafe-inline'forscript-srcbut not'unsafe-eval'— which is the right posture if and only ifMDXRendererruns exclusively on the server.The next.config.mjs comment claims this is server-only:
…but the component file itself has no
"use server"directive or any other build-time assertion that enforces this. If someone importsMDXRendererfrom a client component (knowingly or accidentally — the import path doesn't make the constraint obvious), the eval moves to the browser. CSP would block it (which is itself defense-in-depth), but the error would surface as a runtime failure in the catch block, not at build time.Proposed fix: make the invariant explicit. Two complementary options:
"use server"(orimport "server-only") at the top ofMDXRenderer.tsxso the bundler errors at build time if it gets pulled into a client bundle.velite.config.tsthat fails ifMDXRendereris imported from a file with"use client".Either alone is sufficient; both is belt-and-braces.