Skip to content

Enforce server-only invariant on MDXRenderer's new Function() eval #70

@lwwmanning

Description

@lwwmanning

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:

  1. 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.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsecuritySecurity findings, hardening, and vulnerability disclosure

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions