Back to skill

Security audit

An AI skill for OpenClaw that generates professional diagrams from natural language descriptions using EdrawMax AI APIs.

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent diagram-generation purpose, but it automatically sends user prompts to an external service and uses an unsafe downloader that disables TLS verification and accepts unvalidated download URLs.

Review this skill before installing, especially if diagram prompts may contain sensitive business, personal, or regulated information. It should disclose external processing, restrict network access to expected EdrawMax and storage hosts, keep TLS verification enabled, validate downloaded file types, and enforce download size limits before it is suitable for routine use.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/download_diagram.py:26
Finding

TLS Certificate and Hostname Verification Disabled

Content
View full analysis

Vulnerability Details

File Location: scripts/download_diagram.py, lines 26–37
Vulnerability Type: Improper certificate validation
Risk Level: High

Vulnerable Code

python
def download_file(url: str, output_path: str) -> str:
    """Download a file from URL to output_path. Returns the output_path on success."""
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

    req = urllib.request.Request(url, headers={"User-Agent": "EdrawMax-Skill/2.0"})
    try:
        with urllib.request.urlopen(req, context=ctx, timeout=60) as resp:
            data = resp.read()

Technical Analysis

The downloader explicitly disables both TLS certificate-chain verification and hostname verification. Consequently, an HTTPS connection does not authenticate the remote server. Any certificate, including a self-signed certificate controlled by an attacker, will be accepted.

The timeout only limits how long the request may wait; it does not restore server authentication or protect response integrity. Although the diagram API is expected to return legitimate object-storage URLs, the script cannot determine whether downloaded content genuinely originated from the intended server.

Attack Path

  1. A user requests a diagram, and the service returns PNG and SVG download URLs.
  2. The skill invokes download_diagram.py with those URLs.
  3. An attacker positioned on the network path intercepts an HTTPS download.
  4. The attacker presents an arbitrary certificate and impersonates the remote host.
  5. The script accepts the certificate because certificate and hostname checks are disabled.
  6. The attacker returns substituted PNG or SVG bytes.
  7. The substituted content is written locally and presented as a trusted diagram.

Impact Assessment

A network-positioned attacker can compromise the confidentiality and integrity of downloaded diagram data. The a ...[truncated 536 chars]

Remediation
View remediation

Remediation Suggestions

  1. Preserve the secure defaults of Python's TLS context:

    python
    ctx = ssl.create_default_context()
    

    Remove both of the following assignments:

    python
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    
  2. Fail closed when certificate verification or hostname validation fails. Do not retry using an insecure context.

  3. Require HTTPS URLs and allowlist the expected EdrawMax object-storage domains.

  4. Validate the destination after every redirect so an approved host cannot redirect to an untrusted host or non-HTTPS destination.

  5. Consider certificate pinning only if the service has a reliable certificate-rotation process. Standard platform trust-store validation is preferable to insecure custom verification.

  6. Add automated tests confirming that self-signed certificates, expired certificates, certificates for another hostname, and invalid certificate chains are rejected.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_diagram.py:31
Finding

Unrestricted Diagram URLs and Unbounded Response Downloads

Content
View full analysis

Vulnerability Details

File Location: scripts/download_diagram.py, lines 31–72
Vulnerability Type: Unvalidated remote resource retrieval and unbounded memory consumption
Risk Level: Medium

Vulnerable Code

python
req = urllib.request.Request(url, headers={"User-Agent": "EdrawMax-Skill/2.0"})
try:
    with urllib.request.urlopen(req, context=ctx, timeout=60) as resp:
        data = resp.read()
    os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)
    with open(output_path, "wb") as f:
        f.write(data)
python
parser.add_argument("--png-url", required=True, help="PNG image URL from API response")
parser.add_argument("--svg-url", required=True, help="SVG image URL from API response")
parser.add_argument("--output-dir", default="./edrawmax_output", help="Output directory (default: ./edrawmax_output)")
args = parser.parse_args()

os.makedirs(args.output_dir, exist_ok=True)

timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
png_filename = f"diagram_{timestamp}.png"
svg_filename = f"diagram_{timestamp}.svg"

png_path = os.path.join(args.output_dir, png_filename)
svg_path = os.path.join(args.output_dir, svg_filename)

result = {"png_path": "", "svg_path": ""}

downloaded_png = download_file(args.png_url, png_path)
if downloaded_png:
    result["png_path"] = os.path.abspath(downloaded_png)

downloaded_svg = download_file(args.svg_url, svg_path)
if downloaded_svg:
    result["svg_path"] = os.path.abspath(downloaded_svg)

Technical Analysis

The script accepts caller- or API-supplied URLs without validating their scheme, hostname, port, resolved address, or redirect destination. A URL's parameter name does not guarantee that it points to a PNG or SVG file. The response status, media type, and file signature are not validated before the response is saved with a trusted-looking extension.

In addition, resp.read() reads the entire response into ...[truncated 2259 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse URLs with urllib.parse.urlsplit and accept only https.

  2. Maintain an explicit allowlist of trusted EdrawMax and object-storage hostnames. Reject embedded credentials, unexpected ports, malformed hosts, and hostname suffix tricks.

  3. Resolve destination hosts and reject loopback, link-local, private, multicast, reserved, and unspecified IP ranges unless they are explicitly required. Revalidate the connected destination to reduce DNS-rebinding risk.

  4. Disable automatic redirects or implement a bounded redirect handler that validates every new destination against the same scheme, host, port, and IP policies.

  5. Enforce a strict maximum download size. Check Content-Length when present and stream in bounded chunks while independently counting bytes:

    python
    MAX_BYTES = 20 * 1024 * 1024
    total = 0
    
    with urllib.request.urlopen(req, context=ctx, timeout=60) as resp:
        with open(output_path, "wb") as output:
            while chunk := resp.read(64 * 1024):
                total += len(chunk)
                if total > MAX_BYTES:
                    raise ValueError("Download exceeds the permitted size")
                output.write(chunk)
    
  6. Validate HTTP success status and permit only expected media types. Verify PNG magic bytes rather than relying on Content-Type or the filename.

  7. Parse and sanitize SVG using a security-focused policy. Remove scripts, event handlers, external references, unsafe URI schemes, and risky embedded content. If active SVG is unnecessary, rasterize it in an isolated process or do not download it automatically.

  8. Write to a temporary file with restrictive permissions and atomically rename it only after all validations succeed. Delete partial files on errors.

  9. Apply process-level memory, file-size, disk-quota, and network egress restrictions as defense in depth.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose is diagram generation from natural language, but the implementation guidance also requires downloading remote PNG/SVG files and writing them locally, which is a materially different behavior. This mismatch can hide data flow and filesystem side effects from users and reviewers, increasing the risk of unintended file writes, unsafe content handling, or policy bypass.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill clearly instructs outbound network access to a third-party API, but it does not declare any tool scope such as allowed-tools or permissions. Missing capability declarations weaken sandboxing and review controls, making it easier for a skill to perform network actions without explicit operator awareness.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger phrases are broad enough to match common requests like 'visualize a process' or 'project timeline,' which can cause the skill to activate in contexts where the user did not intend third-party API use or local file downloads. Overbroad activation increases accidental data disclosure and unauthorized external processing risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill instructs sending the user's free-form prompt to an external API but does not require an explicit notice or consent step about remote processing. Because user prompts may contain proprietary, personal, or sensitive business information, silent transmission to a third party creates a real privacy and compliance risk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

This skill depends on a third-party endpoint, which means user content and generated artifact metadata leave the local trust boundary. In context this is expected functionality, but it is still security-relevant because it introduces privacy, integrity, and availability dependence on an external service.

Content

Scanner excerpt · SKILL.md (reported line 32)May include surrounding context.

md
## Step 2 — Call the API

**Base URL:** `https://api.edrawmax.cn/api/ai`

All four endpoints share the same request format:

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The explicit POST request template confirms that user descriptions are transmitted off-platform to a remote API. Even though this is core to the product's function, the transmission is still a true security concern without explicit consent, data-minimization guidance, and scoped network permissions.

Content

Scanner excerpt · SKILL.md (reported line 37)May include surrounding context.

All four endpoints share the same request format:

text
POST https://api.edrawmax.cn/api/ai/skills/generate-{type}
Content-Type: application/json

{"prompt": "<user description>", "lang": "cn", "platform": "web"}

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

The skill depends on a remote endpoint at https://api.edrawmax.cn/api/ai, which means user-provided content leaves the local trust boundary and is processed by an external service. In this skill's context, users are likely to submit detailed workflows, project timelines, org structures, or knowledge maps, making external transmission materially sensitive even if the endpoint itself is expected behavior.

Content

Scanner excerpt · references/api-reference.md (reported line 9)May include surrounding context.

Base URL

text
https://api.edrawmax.cn/api/ai
  • Auth: None required

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The API reference explicitly states that user_id is derived from the X-User-ID header and that free-form prompt content is sent to a remote EdrawMax service, but it provides no user-facing privacy or data-handling warning. In a skill that converts arbitrary natural-language descriptions into diagrams, prompts may contain sensitive business, personal, or project data, so omission of this disclosure can cause unintentional external sharing of user content and identifiers.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · license.txt (reported line 15)May include surrounding context.

text
1. Ownership
   The Software is owned by and remains the exclusive property of
   Wondershare EdrawMax AI Team(万兴图示 AI 团队). All intellectual property rights,
   including but not limited to copyrights, patents, trademarks, and
   trade secrets, are reserved by the EdrawMax AI Team.

2. Restrictions

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The file states that the license is governed by the laws of the People's Republic of China. Under the natural-language policy check, forcing a specific locale or jurisdiction without opt-in or clear region-specific justification can be a policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.