Back to skill

Security audit

Canvas Workspace

Security checks for vulnerabilities and agentic risk

Overview

This canvas image skill is mostly aligned with its purpose, but it needs review because it launches unpinned remote code, stores API keys persistently, fetches arbitrary URLs, and documents a destructive reset endpoint without guardrails.

Install only if you trust the npm package and the Qwen/Gemini endpoints. Prefer setting API keys yourself in a temporary or scoped secret store, avoid giving it private/internal image URLs, and require explicit confirmation before launching setup, fetching URLs, or calling any reset endpoint.

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
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (8)

Tainted flow: 'req' from os.environ.get (line 129, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
req = urllib.request.Request(url, data=data, headers=headers, method="POST")

    try:
        with urllib.request.urlopen(req, timeout=300) as resp:
            result = json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        error_body = e.read().decode("utf-8", errors="replace")
Confidence
90% confidence
Finding
The request URL is derived from GEMINI_BASE_URL, an environment variable, and then used for an authenticated outbound HTTP request carrying the Bearer API key. If an attacker can influence the environment, they can redirect the request to an arbitrary host and capture credentials and prompts, making this a real SSRF/credential-exfiltration risk.

Tainted flow: 'req' from os.environ.get (line 129, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read().decode("utf-8"))
            return result.get("url", "")
    except Exception:
Confidence
82% confidence
Finding
The upload destination is derived from CANVAS_SERVER and used in a POST request with attacker-influenceable base URL semantics. In a compromised or multi-tenant runtime, this can redirect image uploads to an unintended internal or external service, enabling SSRF or unintended data disclosure of generated images.

Tainted flow: 'req' from os.environ.get (line 74, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
def _download_and_upload(image_url: str) -> str:
    """下载远程图片并上传到本地服务器,返回本地 URL"""
    req = urllib.request.Request(image_url, headers={"User-Agent": "Mozilla/5.0"})
    with urllib.request.urlopen(req, timeout=60) as resp:
        image_data = resp.read()
        content_type = resp.headers.get("Content-Type", "image/png")
Confidence
96% confidence
Finding
The script fetches an attacker-controlled URL via urllib.request.urlopen without any allowlist, scheme restriction, or private-address filtering. In an agent context, this creates a classic SSRF primitive that can be used to access internal services, cloud metadata endpoints, or other network-reachable resources, and the downloaded bytes are then relayed into the local canvas upload flow.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The workflow instructs the agent to collect user API keys and persist them as permanent user/system environment variables, which exceeds the immediate task of image generation and creates durable secret exposure. Persisting secrets in shell profiles or user environment stores increases the blast radius across future sessions, other tools, and unrelated processes, and may overwrite existing secure setups.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The privacy section gives a reassuring statement that environment-variable values will not leave the machine, while the workflow explicitly asks the agent to solicit and install API keys into the host environment. Even if the keys are not transmitted externally by the skill itself, this framing is misleading because it downplays the security sensitivity of collecting and persistently storing secrets on the endpoint.

Description-Behavior Mismatch

Medium
Confidence
87% confidence
Finding
The documentation exposes a destructive `reset` capability that clears all canvas data, but the skill metadata/description does not disclose this high-risk action. In an agent setting, undocumented destructive capabilities increase the chance that the agent invokes them unexpectedly or without informed user consent, causing data loss.

Vague Triggers

Medium
Confidence
87% confidence
Finding
The activation keywords are broad and include common terms such as drawing, image generation, editing, and canvas-related words, making accidental auto-activation plausible in unrelated conversations. In an agent setting, overbroad triggering is dangerous because it can cause unsolicited startup of local services, network use, file handling, or secret-collection workflows without strong user intent.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
A destructive wipe endpoint is documented with no warning, confirmation requirement, or safe-use note. In a tool-using agent environment, this omission is dangerous because the model may treat it as a routine operation and erase user workspace contents without clear authorization.

Static analysis

No suspicious patterns detected.