Skip to content

fix: allow unsafe-eval in CSP for DynamicComponentRenderer#3107

Merged
robert-inkeep merged 2 commits intomainfrom
fix/csp-allow-unsafe-eval-for-dynamic-components
Apr 10, 2026
Merged

fix: allow unsafe-eval in CSP for DynamicComponentRenderer#3107
robert-inkeep merged 2 commits intomainfrom
fix/csp-allow-unsafe-eval-for-dynamic-components

Conversation

@anubra266
Copy link
Copy Markdown
Contributor

Summary

  • DynamicComponentRenderer uses react-runner which calls new Function() to compile and render user-authored component code at runtime
  • The CSP script-src directive excluded unsafe-eval in production, silently blocking execution — components rendered as empty <div></div> in prod while working locally
  • Allow unsafe-eval since this is an authenticated admin dashboard that already permits unsafe-inline and external scripts, and the component is by design an eval engine for user-authored code

Test plan

  • Verify DynamicComponentRenderer renders in production (currently broken — empty div)
  • Verify no regression in local dev (already had unsafe-eval)

react-runner uses new Function() to compile and render dynamic component
code at runtime. The CSP script-src directive excluded unsafe-eval in
production, silently blocking execution — rendering an empty div.

unsafe-eval is appropriate here because:
- This is an authenticated admin dashboard, not a public-facing site
- DynamicComponentRenderer is by design an eval engine for user-authored code
- unsafe-inline is already allowed, and PostHog scripts load from external domains
- The code being eval'd is authored by the same authenticated user
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agents-api Ready Ready Preview, Comment Apr 10, 2026 9:12pm
agents-docs Ready Ready Preview, Comment Apr 10, 2026 9:12pm
agents-manage-ui Ready Ready Preview, Comment Apr 10, 2026 9:12pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 10, 2026

🦋 Changeset detected

Latest commit: bce38a6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 10 packages
Name Type
@inkeep/agents-manage-ui Patch
@inkeep/agents-api Patch
@inkeep/agents-cli Patch
@inkeep/agents-core Patch
@inkeep/agents-email Patch
@inkeep/agents-mcp Patch
@inkeep/agents-sdk Patch
@inkeep/agents-work-apps Patch
@inkeep/ai-sdk-provider Patch
@inkeep/create-agents Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@robert-inkeep robert-inkeep enabled auto-merge April 10, 2026 21:03
Copy link
Copy Markdown
Contributor

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-scoped fix. The CSP already permits 'unsafe-inline' and external script hosts, and this is an authenticated admin dashboard — adding 'unsafe-eval' doesn't meaningfully widen the attack surface. react-runner's useRunner relies on new Function() under the hood, so this is required for DynamicComponentRenderer to work in production.

Pullfrog  | View workflow run | Using Claude Opus𝕏

@pullfrog
Copy link
Copy Markdown
Contributor

pullfrog Bot commented Apr 10, 2026

TL;DR — Allows 'unsafe-eval' in the Content Security Policy's script-src directive unconditionally (including production), removing the dev-only gate. This unblocks DynamicComponentRenderer which relies on runtime code evaluation.

Key changes

  • Allow 'unsafe-eval' in CSP for all environments — the script-src directive in buildCsp() previously only included 'unsafe-eval' in development; it is now included unconditionally so that dynamically rendered components work in production.
  • Add changeset — patch bump for @inkeep/agents-manage-ui documenting the fix.

Summary | 2 files | 2 commits | base: mainfix/csp-allow-unsafe-eval-for-dynamic-components

Before: 'unsafe-eval' was conditionally added to script-src only when NODE_ENV !== 'production', blocking runtime eval in production.
After: 'unsafe-eval' is always present in script-src, allowing DynamicComponentRenderer (and any other eval-dependent code) to function in all environments.

agents-manage-ui/src/proxy.ts · .changeset/clever-magenta-bobolink.md

Pullfrog  | View workflow run | Triggered by Pullfrog | Using Claude Opus𝕏

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review Summary

(0) Total Issues | Risk: Low

Analysis

This PR adds 'unsafe-eval' to the production CSP to enable react-runner's new Function() calls for dynamic component rendering in the DynamicComponentRenderer.

Security context assessment:

Factor Assessment
Authentication boundary ✅ Manage UI requires session authentication (non-public paths gated in proxy())
Existing CSP posture CSP already includes 'unsafe-inline' — incremental risk is limited
Feature intent By design an eval engine for admin-authored component code
Code sources AI-generated previews + admin-editable code in playground

Why the change is acceptable:

  1. Scoped to authenticated admins — The manage UI middleware requires a valid session for non-public paths
  2. Existing CSP already permissive'unsafe-inline' is already present, so 'unsafe-eval' is incremental
  3. Functional necessityreact-runner uses new Function() internally; there's no CSP-compliant alternative without architectural changes (e.g., iframe isolation)
  4. Intentional design — The DynamicComponentRenderer exists specifically to evaluate user-authored component code at runtime

💭 Consider (1) 💭

💭 1) proxy.ts:61 Document the security tradeoff

Issue: The 'unsafe-eval' directive is a security control relaxation that future maintainers should understand.

Why: A brief comment would help future engineers understand why this is necessary and what the security implications are.

Fix: Consider adding a comment above line 61 (if the team decides documentation value outweighs the AGENTS.md "No Comments" guideline for security-critical configuration):

// SECURITY: unsafe-eval required for react-runner's new Function() calls
// in DynamicComponentRenderer. Scoped to authenticated admin users only.
"'unsafe-eval'",

Note: This conflicts with the project's AGENTS.md "No Comments" convention — team discretion on whether security config warrants an exception.

Refs: MDN CSP script-src unsafe-eval


✅ APPROVE

Summary: The change is correct, minimal, and well-justified. The security risk is appropriately scoped to authenticated admin users, and the CSP already permits 'unsafe-inline'. The react-runner library requires 'unsafe-eval' for its new Function() internals — this is a functional necessity for the dynamic component preview feature. No blocking issues.

Reviewers (2)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-appsec 1 0 1 0 0 0 0
pr-review-standards 0 0 0 0 0 0 0
Total 1 0 1 0 0 0 0

@github-actions github-actions Bot deleted a comment from claude Bot Apr 10, 2026
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review Summary

(0) Total Issues | Risk: Low

Delta Review

This is a re-review scoped to changes since the prior automated review.

Changes since last review:

  • Added .changeset/clever-magenta-bobolink.md — correctly formatted patch changeset for @inkeep/agents-manage-ui

The changeset is properly formatted, correctly identifies the package (@inkeep/agents-manage-ui), uses the appropriate bump level (patch), and has a clear description matching the PR's purpose.

The core CSP change ('unsafe-eval' addition in proxy.ts) was reviewed and approved in the prior review cycle. No additional findings.


✅ APPROVE

Summary: Clean delta — only a well-formed changeset was added since the last review. The core CSP change was already analyzed and approved. Ship it! 🚀

Reviewers (0)

No sub-reviewers dispatched — delta contained only a changeset file (no code changes to analyze).

@github-actions
Copy link
Copy Markdown
Contributor

Preview URLs

Use these stable preview aliases for testing this PR:

These point to the same Vercel preview deployment as the bot comment, but they stay stable and easier to find.

Raw Vercel deployment URLs

@robert-inkeep robert-inkeep added this pull request to the merge queue Apr 10, 2026
Merged via the queue into main with commit b2c15cd Apr 10, 2026
26 checks passed
@robert-inkeep robert-inkeep deleted the fix/csp-allow-unsafe-eval-for-dynamic-components branch April 10, 2026 21:29
@itoqa
Copy link
Copy Markdown

itoqa Bot commented Apr 10, 2026

Ito Test Report ✅

10 test cases ran. 1 additional finding, 9 passed.

Overall, 9 of 10 tests passed, confirming expected security and routing behavior (CSP with script-src including unsafe-eval on public, protected, and redirect responses), stable deep-link and mobile render-panel behavior, correct unauthenticated redirect-to-login protection, and successful runtime component rendering in data/artifact editors and the agent playground chat path. The key issue found is one medium-severity bug where invalid JSX in the data component Render tab can fail before the in-component ErrorBoundary is mounted, leaving an effectively blank preview instead of a clear fallback error message.

✅ Passed (9)
Category Summary Screenshot
Adversarial Protected deep link correctly redirected anonymous users to login with returnUrl; no editor leakage observed. ADV-1
Edge Deep-link component page remained functional after normal and hard reload, and CSP still included 'unsafe-eval'. EDGE-2
Edge Render panel stayed visible and usable in 390x844 viewport during tab switching and after reload. EDGE-3
Logic Data component Render tab executed runtime JSX and preview updated from Order Count 2 to 3 after sample-data mutation. LOGIC-1
Logic Artifact component Render tab executed runtime JSX and preview updated from Artifact Count 2 to 4 after sample-data mutation. LOGIC-2
Logic Environment credential instability was isolated and the playground correctly rendered a dynamic Activities component through the chat widget path. LOGIC-3
Happy-path Protected agent URL returned 200 with CSP including unsafe-eval after fixture data was seeded. ROUTE-1
Happy-path Unauthenticated /login returned CSP with script-src including unsafe-eval and stayed on login. ROUTE-2
Happy-path Authenticated project-root navigation redirected to /agents with query preserved, and the 307 response included CSP script-src with 'unsafe-eval'. ROUTE-3
ℹ️ Additional Findings (1)

These findings are unrelated to the current changes but were observed during testing.

Category Summary Screenshot
Edge 🟠 Invalid JSX in Render tab can fail without a readable fallback alert, leaving the preview effectively empty. EDGE-1
🟠 Invalid render code surfaces fallback alert
  • What failed: The preview does not reliably show a readable destructive fallback alert for syntax failures; users can see an effectively empty render area instead of actionable error text.
  • Impact: Editors lose clear feedback when runtime code is invalid, which slows debugging and makes render failures look like blank UI states. This can cause repeated failed edits before a user can identify the actual syntax issue.
  • Steps to reproduce:
    1. Open /default/projects/activities-planner/components/activities in an authenticated session.
    2. Switch to Code, replace the render code with syntactically invalid JSX, and return to Render.
    3. Observe that the preview can remain effectively empty instead of consistently showing a readable fallback alert message.
  • Stub / mock context: The component fixture was first corrected to the supported object-based render format so the editor tabs and preview flow were active, then invalid JSX was intentionally entered to verify fallback behavior. No network route mocks or auth bypass behavior were used while confirming this issue.
  • Code analysis: I reviewed the runtime render path in DynamicComponentRenderer and the tabs that call it from data/artifact component render generators. The fallback UI exists, but the boundary is wrapped around the rendered component node inside transformed code, while useRunner compilation/execution happens before that fallback can protect syntax/evaluation failures.
  • Why this is likely a bug: Syntax/evaluation failures can occur in useRunner before the in-transformed ErrorBoundary renders, so the intended fallback path does not reliably cover the full failure surface.

Relevant code:

agents-manage-ui/src/components/dynamic-component-renderer.tsx (lines 23-35)

return js`
  import { ErrorBoundary } from "react-error-boundary";

  ${code}

  export default function App() {
    const props = ${JSON.stringify(props)};
    return (
      <ErrorBoundary fallbackRender={fallbackRender}>
        <${componentName} {...props} />
      </ErrorBoundary>
    );
  }`;

agents-manage-ui/src/components/dynamic-component-renderer.tsx (lines 66-71)

const { element } = useRunner({
  code: transformedCode,
  scope,
});

return <div>{element}</div>;

agents-manage-ui/src/components/data-components/render/component-render-generator.tsx (lines 356-359)

<TabsContent value="render">
  <div className="p-4">
    <DynamicComponentRenderer code={renderCode} props={renderData} />
  </div>
</TabsContent>

Commit: bce38a6

View Full Run


Tell us how we did: Give Ito Feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants