Back to skill

Security audit

Openclaw Research Viz

Security checks for vulnerabilities and agentic risk

Overview

This skill is a legitimate research-report generator, but it automatically publishes report content through under-disclosed hosting paths and includes unsafe upload/report-rendering code that needs review before installation.

Install only if you are comfortable with research summaries and metadata being turned into durable hosted HTML links. Avoid using it for confidential, regulated, private, or internal investigations unless upload is disabled or reviewed first; do not use --no-encrypt for sensitive reports, and treat the upload implementation as needing fixes before trusted use.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/upload-report.js:128
Finding

Shell Command Injection Through R2 Bucket and Report Slug

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/upload-report.js:134
Finding

Runtime Execution of an Unpinned Package Through npx

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/upload-report.js:184
Finding

Automatic Upload to an Undocumented Third-Party Endpoint

Content
View full analysis
{ const req = mod.request({ hostname: url.hostname, port: url.port, path: url.pathname, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), }, }, (res) => { let data = ''; res.on('data', c => data += c); res.on('end', () => { if (res.statusCode >= 200 && res.statusCode < 300) { try { resolve(JSON.parse(data).url); } catch { resolve(`https://r.a2ui.me/r/${slug}.html`); } } else { reject(new Error(`HTTP ${res.statusCode}: ${data}`)); } }); }); req.on('error', reject); req.write(body); req.end(); }); } ``` ```javascript if (process.env.A2UI_R2_BUCKET) { baseUrl = await uploadViaR2(uploadContent, slug); } else if (process.env.A2UI_API_KEY) { baseUrl = await uploadViaAPI(uploadContent, slug); } else { try { baseUrl = await uploadViaPublicAPI(uploadContent, slug); } catch (err) { const localPath = saveLocally(uploadContent, slug); baseUrl = `file://${localPath}`; console.error(`Upload failed (${err.message}). Saved locally: ${localPath}`); } } ``` ### Technical Analysis When neither R2 configuration nor an API key is present, the script does not immediately use the documented local fallback. Instead, it automatically sends the generated viewer ...[truncated 1927 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate-report.js:254
Finding

Stored HTML Injection in Interactive Map Tooltips

Content
View full analysis
\n`; ``` The generated page later retrieves the decoded attribute values and inserts them into `innerHTML`: ```javascript function showTooltip(e,el){var t=document.getElementById('mapTooltip'),r=el.getAttribute('data-region'),i=el.getAttribute('data-info');if(!i)return;t.innerHTML=''+r+'
'+i;t.classList.add('visible');var b=el.closest('.map-container').getBoundingClientRect();t.style.left=(e.clientX-b.left+10)+'px';t.style.top=(e.clientY-b.top-60)+'px'} ``` ### Technical Analysis The `esc()` function protects the initial HTML attribute context by replacing special characters with entities. However, this protection is lost when the browser parses the document. Calling `getAttribute()` returns the attribute's decoded text value. That decoded value is then concatenated into `innerHTML`, where it is interpreted again as markup. This creates a second-order injection vulnerability. A payload can be safely represented in the generated attribute but become active HTML when the tooltip is displayed. The vulnerability is stored because the payload is embedded in the generated report and executes when a viewer later interacts with the map. ### Attack Path 1. Attacker-controlled or insufficiently trusted research data supplies a crafted `region.name` or `region.info`. 2. `esc()` encodes the payload while generating the `data-region` or `data-info` attribute. 3. The report is opened ...[truncated 841 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate-report.js:66
Finding

Dangerous URL Schemes Allowed in Generated Report Links

Content
View full analysis
` ${esc(src.icon || '📄')} ${esc(src.title || src.url || 'Source')} ` ).join('\n'); ``` News URLs are handled in the same way: ```javascript return ``; ``` ### Technical Analysis HTML escaping prevents an input value from breaking out of the quoted `href` attribute, but it does not establish that the URL is safe. Values using schemes such as `javascript:` or potentially dangerous `data:` content remain valid attribute values. The generated report presents these links as research sources or news items, increasing the likelihood that a viewer will trust and click them. `rel="noopener"` protects against opener-based tab attacks but does not neutralize dangerous URL schemes. ### Attack Path 1. Attacker-controlled research data supplies a source or news URL using a dangerous scheme. 2. The generator HTML-escapes the value but performs no scheme validation. 3. The dangerous URL remains in the generated `href`. 4. The report is distributed or upload ...[truncated 622 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the skill functions as a generic public HTML hosting mechanism with user-controlled slugs, it exceeds the declared purpose and can be abused to publish arbitrary content. This makes the skill materially more dangerous than advertised because it creates an unreviewed outbound publication path, not just a visualization helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the skill functions as a generic public HTML hosting mechanism with user-controlled slugs, it exceeds the declared purpose and can be abused to publish arbitrary content. This makes the skill materially more dangerous than advertised because it creates an unreviewed outbound publication path, not just a visualization helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

If the skill functions as a generic public HTML hosting mechanism with user-controlled slugs, it exceeds the declared purpose and can be abused to publish arbitrary content. This makes the skill materially more dangerous than advertised because it creates an unreviewed outbound publication path, not just a visualization helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

If the skill functions as a generic public HTML hosting mechanism with user-controlled slugs, it exceeds the declared purpose and can be abused to publish arbitrary content. This makes the skill materially more dangerous than advertised because it creates an unreviewed outbound publication path, not just a visualization helper.

Content

No source excerpt is available for this finding.

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · demo/polymarket-demo.html (reported line 447)May include surrounding context.

html
<body>

<div class="container">
  <!-- Header -->
  <div class="header fade-in">
    <div class="header-badge"><span class="dot"></span> Research Complete</div>
    <h1>Polymarket Top Opportunities Analysis</h1>

Obfuscated Code

High
Category
Supply Chain
Confidence
91% confidence
Finding

This page ships a large encrypted blob, derives a decryption key from the URL fragment, decrypts it in the browser, and then injects the resulting plaintext directly with document.write(). The obfuscation itself is not the core issue, but it prevents review of the delivered HTML/JS and creates a hidden content execution path; if the encrypted payload or key-generation flow is tampered with, arbitrary active content can run in the user's browser.

Content

Scanner excerpt · demo/test-encrypted.html (reported line 37)May include surrounding context.

html
var ck=await crypto.subtle.importKey('raw',kb,{name:'AES-GCM'},false,['decrypt']);
var iv=Uint8Array.from(atob('dz4m27C9fCr9xAI3'),function(c){return c.charCodeAt(0)});
var at=Uint8Array.from(atob('qp9EgYmBkXQ3swtchjEPTQ=='),function(c){return c.charCodeAt(0)});
var ct=Uint8Array.from(atob('qLjTAbYlHaq0AaQMCvAIhMtJoIz2wpwyPBeqaItCQGMl8QNI6koeMrwJVXaF+AkD99BpmNYBC6ybOhH4YetMMg11r3K7KUHFNGdrv4iH00T7qjZtpXMs+vMn9EfFZuuqmtRIVffXlNUobri64dMMootLg0mQ7MyWnIjyjXjEgFeSXFgg+IKO5J9T8EjqrUctBL56IQ1C9pxpMG6ofolEV3nPhqlt21YnCC20Eo3csy2OrcV4YlhAImaQhfGZZeEeJMs/5/cja+3ArTjWhNwbybHmjvb7FdMb9idVmRDaoM+jYWWiOIxf4DcU0an6lz9K88jnXUuM83bt5Z7v+CsoIogH6gMXF7PEOErnxpEevOx6iKZE05Gr9iQg0GHQCAS5n4qvEWNMBIs8TjgAeHJqzksT33bpg+8vd7RNHfmfOQJyJX4ADhBSX6B0kjGUzWCfvAh6b58g1KEM9esYKc7kWJsgz+uXqKO/vhNjSfl1VvkHWvkhdzc6quWAZLwXUuht7lNzz/b4WKOe+aOA4B0gSn9a+4v0RDF7jZpC84n0xVQAyhD2R9ShMv4M/QkPLHHYqX0RWus7BRuUeN984+n4ES6tkL8CXAo8kQiuPVLA7F6aQ0zk3nEpgtUvCkeyNAOSEiFCseGo3QbEBvZHfZdOJNc8SEgfpDvTPGTrM/a++CuIeGrzMnnSakr+axpTA3aQMneoPNLjQhrHLKoD9lYbER2ulbXTNtSUKsi0o0NvE2Jw+R1UP8Fx6+Tbvkv6gBuIZyraIBR7DLFZ6YR7qI4XPfip/rpgidEjMTKoRIjDaADRM6hjw0aEW7Y04ZDUi252vPv2phm96ui7L9RbzpWKFJ5FTboUOeKBC5arF4qklu7fqinC5WG+8vQfYeWdkq6uv+UKlyvDktR5Qi5YniOSaBYDI69N/jmHatbtwuSaO2+HDqMLw4Mb6Z+aM9dsSuTnqQvlryggn1BZIN6gUL6cy5LpsuXKGydgGla+p9rvcNZ8gmP/EDX4aZiE9GFLqsjPt4ARpocaCDkA9itGOkoKdlRg1GdyONjiX0ixrzxZ/maPspBFPwAmPFfhXGsQJ5Hk7ENdOqnr8l0oWTVKIUIheOhkSp4YFiSP5BQf1tZ0k9NVbckeGn0B63w3Ci/gQCFlyXCrQUUDzRg7LDezYduBeCu8CQOMSLLwIVmYlxi8JC4+/g4fv5rzp+m6dejzjozlROXV1SJDFFdYQwH5vwP4fVCv19l/k2SbRH44eWTJ7VBS7D1hsij59uCvTF6rNo0URXhWGnm6qg3om3COLTTmsOrFRbxPpP/VR9KZsJWUs9/usz5hEd2t5BAyZYxC2g9DeK9z8SY11EqZPlulCRlbGACi2fRkQN21SeKFofhuk6r0OXsfHi5UjYxjrifJ/vp5hJthTK/tspx1Tr086xbcG4EhU/59+HAKDkwUb4xNoCHnrCxdBsYDgWQAy3MDzGLQpjuB7PDVvENKPAhQay46PnSgn3g9N3zJWpKD1nKbD7aPlV4wEioRoAsHbwqdNblsVk8jeul6H93UKZ0oEfSWZJ49XNNG/+cbap/xSH1/URx605xFrf/z5miz015v7SbpMwxiiShVqTHzzV44vQ+nIil0uY+xFqlncsQU+dfGC4vhkyrkJjamSs68Zuc1CJIUh5qjnWxBtTmaGCXwkNvuqElLUJ9nebUMTS9cuHyIiaDW
...[truncated 27 chars]

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/encrypt-report.js (reported line 94)May include surrounding context.

js
status.innerHTML = '<div class="lock-icon">🔒</div><h2 class="error">' + msg + '</h2><p>The decryption key is missing or invalid.</p>';
  }

  // Extract key from URL fragment
  const hash = window.location.hash.slice(1);
  const params = new URLSearchParams(hash);
  const keyB64 = params.get('key');

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding

The skill invokes Node scripts that can read environment variables and perform network operations, but the manifest does not declare any tool scope or allowed-tools restrictions. This weakens reviewability and permission boundaries, making it easier for a skill to exfiltrate data or access credentials without clear operator awareness.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill says reports are uploaded to an external service but does not clearly warn that research content and conversation-derived summaries may leave the local/system boundary. Even with client-side encryption claims, users need explicit notice and consent because metadata, report existence, and mistakes in included content can still create privacy and compliance issues.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest's vague 'Use when' phrases create trigger ambiguity and may cause the skill to be selected for routine analysis tasks where no report sharing is desired. Because this skill can publish or save detailed research artifacts, imprecise routing raises the risk of unintentional disclosure.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation rules are broad enough to trigger on many ordinary research interactions, which increases the chance the skill runs without a clear user request for external publishing. In this skill's context, accidental activation is more dangerous because the workflow culminates in generating shareable artifacts from conversation-derived content.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Directing the skill to extract structured JSON from the conversation and include all research steps can capture sensitive prompts, internal reasoning traces, API outputs, or user-provided confidential data. In a shareable report context, this creates a strong risk of semantic data leakage even if the final answer alone would have been safe to disclose.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The instruction to always include all research steps encourages disclosure of the full intermediate workflow, which can expose sensitive inputs, internal analysis artifacts, and proprietary source material. This is especially dangerous here because the result is designed to be saved locally or shared via a link, turning transient context into a durable disclosure artifact.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The article promotes automatic generation of a shareable report link after research and emphasizes convenience, but it does not clearly warn users that the report content is uploaded to a third-party service and may contain sensitive prompts, retrieved data, internal reasoning traces, or proprietary research context. Even with client-side encryption, disclosure risk remains because anyone with the full URL can access the report, users may share links in chats unintentionally, and the article frames the feature as something that should happen automatically on every deep research task.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The report makes an investment-style recommendation ('safest play') in close proximity to specific market probabilities and confidence scores, while the only disclaimer appears later in the footer rather than near the recommendation itself. In a research-visualization skill, this can mislead users into treating generated content as financial advice or a trading signal, especially because the presentation is polished and data-driven.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This is a true DOM XSS issue. The generated HTML embeds attacker-controlled report data into data-region/data-info attributes with escaping, but the runtime tooltip handler later reads those strings and inserts them with innerHTML ('<strong>'+r+'</strong><br/>'+i), so crafted input such as HTML entities can be decoded by the browser and executed as markup/script in the final report. In this skill context, the report is built from multi-step research context that may include untrusted web/API content, making stored client-side injection more plausible and more dangerous.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The header comment states uploads go to a2ui.me/R2 and emphasizes privacy, but the implementation can send report content to a separate workers.dev endpoint. This discrepancy is dangerous because users and calling agents may trust the documented privacy model while their research output is actually transmitted to a different third-party service, increasing the risk of unintended disclosure of sensitive data.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
84% confidence
Finding

The script invokes npx wrangler without pinning an exact version, so execution depends on whatever package version npx resolves at runtime. In an automated agent context, this creates a supply-chain risk: a compromised, malicious, or behaviorally changed CLI could execute arbitrary code during upload and potentially access report contents, environment variables, or local files.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill promises uploaded clickable reports on a2ui.me, but the code may instead send content to a third-party public workers.dev service or fall back to a local file:// URL. In the context of a research-reporting skill that may process confidential investigation outputs, this mismatch can mislead downstream users and systems about where sensitive data is stored and how links behave.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The --no-encrypt path allows raw HTML reports to be uploaded with no user-facing warning, even though the skill is designed for research outputs that may contain sensitive collected data, analysis, or conclusions. Because the script's surrounding documentation strongly emphasizes privacy-preserving encrypted sharing, this silent opt-out can cause accidental public disclosure when users or agents disable encryption.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code implements a public unauthenticated HTML upload-and-hosting service: any client can POST arbitrary HTML to /api/upload and later retrieve it from /r/.html. This materially exceeds the stated 'research visualizer' purpose and creates an attacker-controlled hosting surface suitable for phishing, malware delivery, and brand-abuse under the service's domain.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The endpoint accepts any string in body.html and persists it as text/html without sanitization, policy checks, or tying content to a completed research task. In the context of a skill that should visualize research results, this unjustified arbitrary publishing capability is dangerous because it can be repurposed as a general-purpose attacker-controlled web host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code performs a file write to R2 by persisting the provided HTML content, which is a safety-relevant operation affecting user data handling. There is no confirmation prompt, user-visible disclosure, or explanatory comment/docstring near the write indicating that submitted content will be stored and later served.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The document declares lang="en", which sets an English-only language expectation for the content. Under the policy rule, forcing a specific language without opt-in or clear justification can be a natural-language locale policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The HTML root sets lang="en", which establishes English as the page language, and the visible content is also entirely English. Under the policy criteria, forcing a specific language without user opt-in or documented justification is a natural-language locale policy issue.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/upload-report.js:119