paperclipai/paperclip · error · Error

Public report contains active or remote HTML: ${file}

Error message

Public report contains active or remote HTML: ${file}

What it means

Thrown by validatePublicProtocolEvalReport when a non-rich-attempt HTML file in the public report matches one of the ACTIVE_HTML_PATTERNS: <script>, <iframe>, <object>, <embed>, <form> tags, inline on* event handlers, javascript: URLs, or absolute http(s):// src/href references. The published report must be fully static with no executable or remote-loading content, so active or remote-loading HTML is rejected before S3 upload.

Source

Thrown at packages/paperclip-runner/scripts/publish-runner-protocol-eval-history.mjs:191

        );
      continue;
    }
    const content = await readFile(absolute, "utf8");
    const richAttempt = /^attempts\/[^/]+\/index\.html$/.test(file);
    const payload = richAttempt
      ? validatePublicViewerPage(content, viewer.index)
      : null;
    if (!richAttempt) {
      for (const pattern of CREDENTIAL_PATTERNS) {
        if (pattern.test(content))
          throw new Error(
            `Public report contains credential/session material: ${file}`,
          );
      }
      if (extname(file) !== ".html") continue;
      for (const pattern of ACTIVE_HTML_PATTERNS) {
        if (pattern.test(content))
          throw new Error(
            `Public report contains active or remote HTML: ${file}`,
          );
      }
    }
    const navigation = payload
      ? [
          payload.navigation?.suiteHref,
          payload.navigation?.previous?.href,
          payload.navigation?.next?.href,
        ].filter(Boolean)
      : [];
    for (const href of [...internalHtmlHrefs(content), ...navigation]) {
      if (typeof href !== "string" || /[?:\\]|^\/|^[a-z]+:/i.test(href))
        throw new Error(`Unsafe report navigation in ${file}`);
      const clean = href.split("#", 1)[0].split("?", 1)[0];
      const target = resolve(
        root,
        ...file.split("/").slice(0, -1),

View on GitHub (pinned to 01ad858492)

Solutions

  1. Locate the active HTML element or remote URL in the named file and remove it or replace with a static, relative reference.
  2. HTML-escape all agent-generated content when rendering report pages so embedded code displays as text, not markup.
  3. Serve all assets locally (viewer/assets/*.js|css|woff2) instead of linking remote CDNs.
  4. If the page is a rich attempt, render it as attempts/<id>/index.html (rich-attempt path) instead of the legacy attempts/<id>.html name.

Example fix

// before
<script src="https://cdn.example.com/highlight.js"></script>
// after
<link rel="stylesheet" crossorigin href="./assets/app.css">
Defensive patterns

Strategy: validation

Validate before calling

const ACTIVE_HTML_PATTERNS = [
  /<script\b/iu, /<iframe\b/iu, /<object\b/iu, /<embed\b/iu, /<form\b/iu,
  /\son[a-z]+\s*=/iu, /javascript\s*:/iu,
  /(?:src|href)\s*=\s*["'](?:https?:)?\/\//iu,
];
export const isStaticSafeHtml = (html) => !ACTIVE_HTML_PATTERNS.some((p) => p.test(html));

Type guard

const isStaticSafeHtml = (content) => !ACTIVE_HTML_PATTERNS.some((p) => p.test(content));

Try / catch

try {
  await validatePublicProtocolEvalReport(reportRoot, { viewerRoot });
} catch (err) {
  if (String(err.message).startsWith("Public report contains active or remote HTML")) {
    console.error("Escape embedded agent HTML or remove script/iframe/remote references in the named page.");
  }
  throw err;
}

Prevention

When it happens

Trigger: Publishing a report whose index.html, tests/*.html, or attempts/<id>.html (legacy plain pages) contains e.g. <script src="https://cdn..."></script>, an <iframe>, an onclick= attribute, a javascript: link, or any src/href pointing at an absolute http(s) URL.

Common situations: Report generator pastes agent output containing raw HTML including script tags without escaping; a marketing/analytics snippet is left in the report template; screenshots are referenced via absolute CDN URLs instead of bundling assets locally; rich-viewer pages are misnamed as legacy attempts/<id>.html so they skip the rich-attempt path and get the strict static-HTML scan.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/430c4e3b7b9c0d8f. Report an issue: GitHub.