Back to skill

Security audit

test

Security checks for vulnerabilities and agentic risk

Overview

VibePolish is a coherent local visual editor, but its browser-to-filesystem bridge gives opened project code too much access to files and write actions inside the selected project.

Use this skill only with projects you trust. Avoid opening directories that contain .env files, private keys, credentials, or unrelated sensitive files, and commit or back up work before using save/apply or rollback features.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/open-runtime.mjs:10068
Finding

Untrusted project code can invoke a privileged CDP bridge to read project files

Content
View full analysis

Vulnerability Details

File Location: scripts/open-runtime.mjs:10068-10173
Related Locations: assets/vibepolish.html:29, assets/vibepolish-runtime.js:12400-12405, scripts/open-runtime.mjs:8219-8227, scripts/open-runtime.mjs:10414-10434
Vulnerability Type: Unauthenticated privileged browser-to-filesystem bridge
Risk Level: High

Complete Code Snippets

The project is loaded into an iframe that permits scripts and retains its origin:

html
<iframe id="dt-frame" sandbox="allow-scripts allow-same-origin allow-forms allow-modals"></iframe>

Project mode navigates that iframe to a page served from the same local origin as the trusted editor wrapper:

js
frame.removeAttribute("srcdoc");
frame.src = runtimeSource.url;

The launcher installs a CDP binding and accepts requests without validating the caller's frame, execution context, origin, or possession of an authorization capability:

js
cdp.on("Runtime.bindingCalled", async (event) => {
  if (event.name !== "__dtCdpStyleProviderBinding") return;
  let payload;
  try {
    payload = JSON.parse(event.payload || "{}");
    const request = payload.request || {};
    const isExclusive = [
      "applyStyleTexts",
      "captureReviewImage",
      "captureSourceState",
      "exportProject",
      "exportProjectSourceCopy",
      "exportSingleHtmlPackage",
      "applySource",
      "restoreSessionTransaction"
    ].includes(request.action);
    const readGeneration = isExclusive ? 0 : ++latestReadGeneration;
    providerQueue = providerQueue.catch(() => void 0).then(async () => {
      await styleProviderReady;
      return cdpWinningRulesForRequest(cdp, request, knownStyleSheetIds, {
        debug: !!meta.debug,
        projectRoot: meta.projectRoot || "",
        sourceFile: meta.sourceFile || "",
        projectOrigin: meta.projectOrigin || "",
        knownStyleSheetIds,
        styleSheetHeaders,
        liveStyleSheetTextBySourceKey,
        sourceStyleSheetBaseline
...[truncated 5626 chars]
Remediation
View remediation

Remediation Suggestions

  1. Bind privileged operations only to the trusted editor context

    • Record the editor wrapper's CDP execution-context ID and frame ID.
    • Reject every Runtime.bindingCalled event not originating from that exact context.
    • Do not install the filesystem-capable binding globally across all frames.
  2. Separate the editor and project into different origins

    • Serve untrusted project content from a distinct origin or randomized port.
    • Ensure the project iframe cannot access the editor's global objects.
    • Remove allow-same-origin from the iframe sandbox if application functionality permits it.
  3. Require an unguessable per-session capability

    • Generate a cryptographically random capability in the Node.js launcher.
    • Deliver it only to the trusted editor context.
    • Authenticate every privileged request and bind the capability to the expected frame and session.
    • Do not expose the capability in the project DOM, query string, or globals reachable from the iframe.
  4. Restrict file reads

    • Maintain an explicit allowlist of files loaded as editable documents or stylesheets.
    • Reject captureSourceState paths not already registered as part of the editing session.
    • Explicitly deny common sensitive files and directories such as .env, credential files, private keys, and hidden configuration unless the user separately authorizes them.
  5. Restrict mutation operations

    • Require explicit trusted-editor user interaction before applySource or restoration operations.
    • Use a short-lived confirmation token tied to the exact paths and content hashes being modified.
    • Reject write requests initiated from project frames, regardless of request payload validity.
  6. Harden the response channel

    • Return privileged results only to the authenticated trusted editor context.
    • Avoid evaluating result callbacks in a context selected solely by attacker-provided request identifiers.

...[truncated 313 chars]

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (15)

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · assets/vibepolish-runtime.js (reported line 10362)May include surrounding context.

js
const ancestorSelector = ancestorTargetSelector(classificationSelector, ownerTargets, scopes, propertyTargets, breadth);
    if (ancestorSelector) return ancestorSelector;
    for (const rule of candidateRules) {
      if ((rule == null ? void 0 : rule.selector) && selectorMatchesExactDocumentSet(rule.selector, propertyTargets, breadth)) return rule.selector;
    }
    const nth = nthFallbackSelector(propertyTargets, scopes, { preferSharedParent: breadth === "single" });
    if (nth && selectorMatchesTargetsExactly(nth, scopes, propertyTargets, breadth)) {

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · assets/vibepolish-runtime.js (reported line 10493)May include surrounding context.

js
const ancestorSelector = ancestorTargetSelector(classificationSelector, ownerTargets, scopes, propertyTargets, breadth);
    if (ancestorSelector) return ancestorSelector;
    for (const rule of candidateRules) {
      if ((rule == null ? void 0 : rule.selector) && selectorMatchesExactDocumentSet(rule.selector, propertyTargets, breadth)) return rule.selector;
    }
    const nth = nthFallbackSelector(propertyTargets, scopes, { preferSharedParent: breadth === "single" });
    if (nth && selectorMatchesTargetsExactly(nth, scopes, propertyTargets, breadth)) {

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · assets/vibepolish-runtime.js (reported line 10892)May include surrounding context.

js
const ancestorSelector = ancestorTargetSelector(classificationSelector, ownerTargets, scopes, propertyTargets, breadth);
    if (ancestorSelector) return ancestorSelector;
    for (const rule of candidateRules) {
      if ((rule == null ? void 0 : rule.selector) && selectorMatchesExactDocumentSet(rule.selector, propertyTargets, breadth)) return rule.selector;
    }
    const nth = nthFallbackSelector(propertyTargets, scopes, { preferSharedParent: breadth === "single" });
    if (nth && selectorMatchesTargetsExactly(nth, scopes, propertyTargets, breadth)) {

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/open-runtime.mjs (reported line 11344)May include surrounding context.

js
const ancestorSelector = ancestorTargetSelector(classificationSelector, ownerTargets, scopes, propertyTargets, breadth);
    if (ancestorSelector) return ancestorSelector;
    for (const rule of candidateRules) {
      if ((rule == null ? void 0 : rule.selector) && selectorMatchesExactDocumentSet(rule.selector, propertyTargets, breadth)) return rule.selector;
    }
    const nth = nthFallbackSelector(propertyTargets, scopes, { preferSharedParent: breadth === "single" });
    if (nth && selectorMatchesTargetsExactly(nth, scopes, propertyTargets, breadth)) {

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

This runtime exposes powerful primitives to read project files, export full project archives, apply source changes to disk, and roll back prior content through a CDP-accessible bridge. Even if intended for local editing workflows, any script running in the instrumented page or any party with access to the debugging/session channel could invoke these operations and cause unauthorized source disclosure or filesystem modification.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/open-runtime.mjs (reported line 11171)May include surrounding context.

js
}
    index = close;
  }
  return rules;
}
function parseRuleHeader(rawHeader) {
  let offset = 0;

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The design specifies fixed Chinese labels such as "宽度", "上留白", "宽:", and "高:" for the layout editor UI. This is a natural-language locale policy issue because the document mandates a specific language in the product interface without offering a user language choice or explaining a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The document requires default-value text to be displayed with the Chinese suffix "(默认)", which hard-codes a specific language into the interface. Because no user opt-in or region-specific rationale is provided, this violates the language/locale policy criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The UI structure section mandates labels like "选区", "复制", "编辑", "内容", "外观", and "布局". These fixed strings indicate the skill is prescribing a single interface language without opt-in or documented justification, matching the natural-language policy violation rule.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This JavaScript file contains extensive user-facing strings in Chinese, such as the status text at L07118, and the UI consistently presents labels, tooltips, and guidance in that language. There is no visible language selection, locale negotiation, or documented justification that this skill is region-specific, so it appears to enforce a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The HTML root sets lang="zh-CN", which indicates the interface/content is fixed to Simplified Chinese. Under the policy, forcing a specific language without user opt-in or documented justification is a natural-language locale violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The rollback path writes file contents back to disk automatically once hash checks pass, but provides no user-facing confirmation in this script. While intended as recovery logic, it is still a mutation primitive that could be abused to overwrite local files if an attacker can supply or trigger a crafted session transaction.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script launches Chrome with a remote debugging port and injects a privileged CDP bridge into the page, creating a high-trust control channel between page/runtime code and local tooling. If another local process or untrusted page content can reach that bridge, it can inspect the DOM, alter styles, capture screenshots, and trigger source-level operations exposed by the same runtime.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code applies project source changes directly to disk with no confirmation or interactive disclosure in the execution path. In the context of a browser-driven runtime with injected automation, silent writes increase the risk of accidental or unauthorized modification of local project files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

This function starts a Chrome/Chromium process with remote debugging enabled, which is a subprocess execution with notable system impact. While the script later prints connection details, there is no clear disclosure immediately before launch that a browser subprocess will be spawned and configured with a debugging port and temporary profile.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.dynamic_code_execution, suspicious.obfuscated_code

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/open-runtime.mjs:10026

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
assets/vibepolish-runtime.js:18511

Potential obfuscated payload detected.

Warn
Code
suspicious.obfuscated_code
Location
scripts/open-runtime.mjs:678