Back to skill

Security audit

SVG Architecture Diagram

Security checks for vulnerabilities and agentic risk

Overview

This diagram skill is mostly coherent, but its screenshot helper can load arbitrary web or file URLs and its delivery instructions can send generated diagrams to Telegram without a clear warning.

Review before installing. Use the skill only for local HTML diagrams you or your agent just created, avoid passing URLs or file:// paths to the screenshot script, and treat Telegram delivery as sending the diagram to an external service that may expose sensitive architecture details.

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

Warning
Location
scripts/screenshot.py:33
Finding

Unrestricted Browser Navigation Enables Internal Network and Local File Access

Content
View full analysis

Vulnerability Details

File Location: scripts/screenshot.py, lines 33–39 and 57
Vulnerability Type: Unrestricted URL and URI navigation
Risk Level: Medium

Vulnerable Code

python
html_path = args.html
if not html_path.startswith(("http://", "https://", "file://")):
    abs_path = os.path.abspath(html_path)
    if not os.path.exists(abs_path):
        print(f"Error: File not found: {abs_path}", file=sys.stderr)
        sys.exit(1)
    html_path = f"file://{abs_path}"

# ...

page.goto(html_path, wait_until="networkidle")

Technical Analysis

The renderer describes its input as a path to an HTML file, but it explicitly accepts arbitrary http://, https://, and file:// URIs. Inputs using these schemes bypass the existence check and are passed directly to Playwright's page.goto().

Because Chromium runs with the host's network and filesystem visibility, an attacker who can control the input argument can direct it to:

  • Loopback services such as http://127.0.0.1:<port>/
  • Private-network services
  • Cloud instance metadata endpoints
  • Sensitive files available through file:// URIs

This creates an SSRF-like browser navigation primitive and exceeds the access required to render a local diagram. Successful responses can be captured in the generated screenshot.

Attack Path

  1. An attacker gains influence over the value passed as the script's html argument.
  2. The attacker supplies an internal URL, metadata endpoint, or sensitive file:// URI.
  3. The scheme check accepts the input without host, path, or origin validation.
  4. Headless Chromium navigates to the target using the host's network and filesystem access.
  5. The rendered response is saved to the attacker-selected or default PNG output.
  6. The screenshot may then be disclosed through the Skill's normal media-delivery workflow.

Impact Assessment

A successful exploit can expose content from HTTP services reachable only from the rendering host or from local fi ...[truncated 385 chars]

Remediation
View remediation

Remediation Suggestions

  1. Accept only local HTML files and reject all URI schemes, including http://, https://, and caller-supplied file:// values.
  2. Resolve the input with pathlib.Path.resolve() and verify that it is a regular file with an .html or .htm extension.
  3. Restrict resolved inputs to a designated workspace using Path.is_relative_to() or an equivalent canonical-path containment check.
  4. Construct the file URI internally with Path.as_uri() rather than accepting one from the caller.
  5. Use Playwright request routing to abort all non-file: requests during rendering:
python
page.route(
    "**/*",
    lambda route: route.continue_()
    if route.request.url.startswith("file:")
    else route.abort(),
)
  1. Bundle fonts and other assets locally so network access can be disabled without affecting output.
  2. Store output only under an approved directory and validate its canonical path if untrusted callers can control the output argument.

A hardened input flow could use:

python
from pathlib import Path

workspace = Path.cwd().resolve()
input_path = Path(args.html).resolve()

if (
    not input_path.is_file()
    or input_path.suffix.lower() not in {".html", ".htm"}
    or not input_path.is_relative_to(workspace)
):
    parser.error("Input must be a local HTML file inside the workspace")

html_path = input_path.as_uri()
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (22)

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 · references/example-hermes.html (reported line 19)May include surrounding context.

html
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1600 1000" width="1600" height="1000">
  <defs>
    <!-- 箭头标记 -->
    <marker id="arr-indigo" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
      <path d="M0,0 L8,3 L0,6 Z" fill="#6366f1"/>
    </marker>

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 · references/example-hermes.html (reported line 132)May include surrounding context.

html
<line x1="622" y1="292" x2="622" y2="302" stroke="#6366f1" stroke-width="1.5" marker-end="url(#arr-indigo)"/>
  <line x1="622" y1="347" x2="622" y2="357" stroke="#6366f1" stroke-width="1.5" marker-end="url(#arr-indigo)"/>
  <line x1="622" y1="402" x2="622" y2="412" stroke="#f59e0b" stroke-width="1.5" marker-end="url(#arr-amber)"/>
  <!-- 循环回到顶部 -->
  <path d="M545,430 L520,430 L520,215 L542,215" stroke="#6366f1" stroke-width="1.5" fill="none" stroke-dasharray="5,3" marker-end="url(#arr-indigo)"/>
  <text x="510" y="320" font-size="9" fill="#6366f1" transform="rotate(-90, 510, 320)" text-anchor="middle">循环</text>

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 · references/example-hermes.html (reported line 147)May include surrounding context.

html
<text x="800" y="272" font-size="12" font-weight="700" fill="#d97706">skill_manage 工具</text>
  <text x="800" y="290" font-size="11" fill="#6b7280">create / read / update / delete / list</text>

  <!-- Pattern Extraction -->
  <rect x="780" y="318" width="340" height="55" rx="10" fill="#fff" stroke="#f59e0b" stroke-width="2" filter="url(#shadow)"/>
  <text x="800" y="340" font-size="11" font-weight="700" fill="#d97706">Pattern Extraction</text>
  <text x="800" y="358" font-size="10" fill="#6b7280">从执行轨迹提取可复用工作流</text>

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 · references/example-hermes.html (reported line 194)May include surrounding context.

html
<text x="330" y="630" font-size="10" fill="#6b7280">Generate → Evaluate → Prune</text>
  <text x="330" y="648" font-size="10" fill="#9ca3af">→ Augment 循环精炼</text>

  <!-- GEPA 循环箭头 -->
  <path d="M425,668 Q425,690 370,690 Q315,690 315,668" stroke="#8b5cf6" stroke-width="1.5" fill="none" stroke-dasharray="4,3" marker-end="url(#arr-purple)"/>
  <text x="370" y="700" text-anchor="middle" font-size="9" fill="#8b5cf6">循环精炼</text>

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 · references/example-openclaw.html (reported line 45)May include surrounding context.

html
</filter>
  </defs>

  <!-- ========== 标题 ========== -->
  <text x="800" y="38" text-anchor="middle" font-size="22" font-weight="700" fill="#1f2937">OpenClaw 完整技术架构图</text>
  <text x="800" y="58" text-anchor="middle" font-size="12" fill="#9ca3af">Multi-Channel AI Agent Platform · Gateway → Sessions → Agent Loop → Tools</text>

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 · references/example-openclaw.html (reported line 154)May include surrounding context.

html
<line x1="340" y1="395" x2="377" y2="395" stroke="#10b981" stroke-width="2" marker-end="url(#arr-green)"/>
  <text x="348" y="388" font-size="9" fill="#10b981" font-weight="500">上下文</text>

  <!-- ========== 第三层中右:Sessions + Cron ========== -->
  <rect x="700" y="240" width="240" height="40" rx="10" fill="#10b981" filter="url(#shadow)"/>
  <text x="820" y="265" text-anchor="middle" font-size="13" font-weight="700" fill="#fff">📋 Sessions 会话管理</text>

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 · references/example-openclaw.html (reported line 154)May include surrounding context.

html
<line x1="340" y1="395" x2="377" y2="395" stroke="#10b981" stroke-width="2" marker-end="url(#arr-green)"/>
  <text x="348" y="388" font-size="9" fill="#10b981" font-weight="500">上下文</text>

  <!-- ========== 第三层中右:Sessions + Cron ========== -->
  <rect x="700" y="240" width="240" height="40" rx="10" fill="#10b981" filter="url(#shadow)"/>
  <text x="820" y="265" text-anchor="middle" font-size="13" font-weight="700" fill="#fff">📋 Sessions 会话管理</text>

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 · references/example-openclaw.html (reported line 178)May include surrounding context.

html
<!-- Gateway → Sessions -->
  <path d="M700,210 L820,210 L820,237" stroke="#10b981" stroke-width="2" fill="none" marker-end="url(#arr-green)"/>

  <!-- Gateway → Cron -->
  <path d="M900,210 L950,210 L950,425 L940,425" stroke="#f59e0b" stroke-width="2" fill="none" stroke-dasharray="6,4" marker-end="url(#arr-amber)"/>

  <!-- ========== 第三层右:LLM Providers ========== -->

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 · references/example-openclaw.html (reported line 178)May include surrounding context.

html
<!-- Gateway → Sessions -->
  <path d="M700,210 L820,210 L820,237" stroke="#10b981" stroke-width="2" fill="none" marker-end="url(#arr-green)"/>

  <!-- Gateway → Cron -->
  <path d="M900,210 L950,210 L950,425 L940,425" stroke="#f59e0b" stroke-width="2" fill="none" stroke-dasharray="6,4" marker-end="url(#arr-amber)"/>

  <!-- ========== 第三层右:LLM Providers ========== -->

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 · references/example-openclaw.html (reported line 281)May include surrounding context.

html
<text x="870" y="698" text-anchor="middle" font-size="11" font-weight="600" fill="#475569">MCP</text>
  <text x="870" y="715" text-anchor="middle" font-size="9" fill="#9ca3af">外部工具协议</text>

  <!-- Agent Loop → Tools -->
  <path d="M200,592 L200,622" stroke="#64748b" stroke-width="2" fill="none" marker-end="url(#arr-slate)"/>
  <text x="210" y="612" font-size="9" fill="#64748b" font-weight="500">工具调用</text>

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 · references/example-openclaw.html (reported line 295)May include surrounding context.

html
<text x="980" y="732" font-size="10" fill="#6b7280">• Hook: tool lifecycle + gateway pipeline</text>
  <text x="980" y="748" font-size="10" fill="#6b7280">• lossless-claw · clawguard-bench ...</text>

  <!-- Plugin ↔ Agent Loop -->
  <path d="M960,645 L400,530" stroke="#f59e0b" stroke-width="2" fill="none" stroke-dasharray="6,4" marker-end="url(#arr-amber)"/>
  <text x="680" y="578" font-size="10" fill="#d97706" font-weight="500">插件钩子</text>

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This manifest-style description includes a broad activation condition that could match many ordinary diagram requests beyond architecture-specific use cases. Because it lacks exclusion conditions or tighter constraints, the skill may be invoked in situations where a more appropriate diagramming or visualization skill should handle the request.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill includes a command to send generated media via Telegram, which is outside the core responsibility of creating/rendering diagrams. This expands the skill from local content generation into external data transmission, creating a risk that sensitive diagrams or embedded metadata could be exfiltrated without adequate review.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documented Telegram command performs external transmission and includes force-send behavior, but the skill provides no warning that generated diagrams may leave the local environment. In practice, users may send internal architecture diagrams containing sensitive infrastructure details to third-party services without informed consent or review.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/example-hermes.html (reported line 145)May include surrounding context.

html
<!-- skill_manage 工具 -->
  <rect x="780" y="250" width="340" height="55" rx="10" fill="#fff" stroke="#f59e0b" stroke-width="2" filter="url(#shadow)"/>
  <text x="800" y="272" font-size="12" font-weight="700" fill="#d97706">skill_manage 工具</text>
  <text x="800" y="290" font-size="11" fill="#6b7280">create / read / update / delete / list</text>

  <!-- Pattern Extraction -->
  <rect x="780" y="318" width="340" height="55" rx="10" fill="#fff" stroke="#f59e0b" stroke-width="2" filter="url(#shadow)"/>

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script explicitly allows http:// and https:// inputs, which expands a local SVG/HTML screenshot utility into a remote web fetcher. In Playwright, loading attacker-controlled remote pages can trigger outbound network access, execute arbitrary page JavaScript in the browser context, and expose the host to SSRF-style access to internal resources or unintended interaction with network-reachable services.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Accepting arbitrary remote pages is an unnecessary capability for a diagram-rendering tool whose stated purpose is to screenshot locally produced SVG-in-HTML output. This increases attack surface by letting untrusted external content run in a headless browser, potentially causing data exfiltration via network requests, internal network probing, or abuse of the host environment through browser features.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

Line L002 sets the page language to zh-CN, and the content throughout the diagram is primarily Chinese. This is a natural-language locale constraint, but the file does not indicate that the skill is region-specific or that users can opt into another language.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The template imports a remote Google Fonts stylesheet, which breaks the 'pure SVG in HTML' local-rendering assumption and causes network access during rendering. In a screenshotting pipeline such as Playwright, this can leak request metadata, introduce nondeterministic output, and fail in restricted or offline environments.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The document sets the page language to "zh-CN", and the visible content is predominantly Chinese, which imposes a specific language/locale on users. Under the policy, locale-specific behavior should either be optional for the user or clearly documented as a justified regional constraint.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The HTML imports a Google Fonts stylesheet from an external domain, which causes network access during rendering and leaks metadata such as IP address, timing, and user agent to a third party. For a skill described as producing pure local SVG/HTML screenshots, this is unnecessary external dependency and weakens isolation and reproducibility.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The docstring says the default scale is 2 and presents that as the optimized default, while the argument parser actually sets --scale to default to 4. This is a direct documentation-to-code contradiction about the script's actual behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.