Back to skill

Security audit

画布连接器

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its stated canvas-connection purpose, but it asks the agent to download and run an external local connector in the background and exposes a connector token in a browser URL.

Review before installing. Only use this skill if you trust the publisher and the official aicanvas.miaotuntu.com connector distribution, because normal use downloads local Node.js code, runs it in the background, and passes a connector token to the canvas page. Confirm the start command yourself, avoid sharing the generated pageUrl, and stop the canvas-agent.mjs process when you are done.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/connect.mjs:25
Finding
Externally Hosted Connector Is Downloaded and Prepared for Local Execution<![CDATA[ ## Vulnerability Details **File Location**: `scripts/connect.mjs:25-26, 93-116` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Critical ### Complete Code Snippet ```js const OFFICIAL_SOURCE = "https://aicanvas.miaotuntu.com/downloads/lobster-canvas-agent.mjs"; const OFFICIAL_SOURCE_SHA256 = "f4261772d0039f7949b22ec965b97dbe6395e8314b67d02c4cae84a4314b24d7"; try { mkdirSync(configDir, { recursive: true }); if (source.startsWith("/") || source.startsWith(".")) { copyFileSync(resolve(source), target); } else { const expected = expectedSha || (source === OFFICIAL_SOURCE ? OFFICIAL_SOURCE_SHA256 : ""); const res = await fetch(source, { signal: AbortSignal.timeout(60000) }); if (!res.ok) throw new Error(`Download failed: HTTP ${res.status}`); const buf = Buffer.from(await res.arrayBuffer()); const actual = sha256(buf); if (actual !== expected) { throw new Error("Connector SHA-256 verification failed"); } writeFileSync(target, buf); } } catch (error) { process.exit(1); } console.log( JSON.stringify({ ok: false, needStart: true, url, connectorFile: target, startCommand: `nohup node ${target} >> ${join(configDir, "connector.log")} 2>&1 &`, }), ); ``` The original source contains localized error and hint strings omitted from the excerpt above; they do not affect the vulnerable execution flow. ### Technical Analysis The Skill downloads a Node.js program from an external service and stores it as `~/.infinite-canvas/canvas-agent.mjs`. It then returns a shell command instructing the calling Agent to execute that downloaded program in the background. The SHA-256 check is a meaningful integrity safeguard: the downloaded bytes must match the digest embedded in the reviewed Skill. It prevents an ordinary server compromise from silently substituting a different payload without also ...[truncated 2215 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bundle the complete connector source in the Skill so that all executed code is available for review. 2. Build distributable connector artifacts through a reproducible and independently verifiable build process. 3. If runtime retrieval is unavoidable, publish signed releases and verify a signature rooted in a separately trusted publisher key, in addition to SHA-256 verification. 4. Require explicit, informed user approval immediately before running downloaded code. Display the source URL, destination path, signer identity, digest, and requested capabilities. 5. Run the connector with reduced privileges and a restricted environment, filesystem allowlist, and network policy. 6. Avoid returning an executable shell command as data. Use a controlled launcher with strict argument handling and lifecycle management. 7. Pin releases by immutable version and retain prior signed artifacts for independent verification. 8. Document the connector's local API, outbound connections, accessible data, and shutdown behavior. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/connect.mjs:52
Finding
Local Connector Bearer Token Is Embedded in a Browser URL<![CDATA[ ## Vulnerability Details **File Location**: `scripts/connect.mjs:52-80` **Vulnerability Type**: Sensitive credential exposure through URL construction **Risk Level**: High ### Complete Code Snippet ```js const readToken = () => { try { return String(JSON.parse(readFileSync(configFile, "utf8")).token || ""); } catch { return ""; } }; const isOfficialCanvas = (value) => !value || value === OFFICIAL_CANVAS; const pageUrl = (token) => { const base = canvas || OFFICIAL_CANVAS; if (!isOfficialCanvas(canvas)) return `${base}/app/#agentUrl=${encodeURIComponent(url)}`; return `${base}/app/#agentUrl=${encodeURIComponent(url)}&agentToken=${encodeURIComponent(token)}`; }; if (await health()) { const token = readToken(); console.log( JSON.stringify({ ok: true, url, tokenMasked: mask(token), pageUrl: pageUrl(token), alreadyRunning: true, needStart: false, }), ); process.exit(0); } ``` ### Technical Analysis The script reads the connector token from `~/.infinite-canvas/canvas-agent.json` and embeds the complete value in the `agentToken` fragment parameter of `pageUrl`. Although the separate `tokenMasked` field is masked, the full credential remains present in the JSON output through `pageUrl`. The fragment portion of a URL is normally not transmitted in the HTTP request to the server. This reduces exposure through ordinary server access logs. However, JavaScript executing under the opened canvas origin can read `window.location.hash` and extract the token. The full URL can also be exposed through Agent transcripts, copying and pasting, screenshots, browser state, diagnostics, extensions, or other local software. Exact comparison with the official canvas URL prevents automatic token inclusion for custom canvas addresses. This is a useful restriction, but it deliberately grants remotely served JavaScript from the offic ...[truncated 2181 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not place long-lived bearer tokens in URLs, URL fragments, command output, Agent messages, or browser history. 2. Replace the token with a short-lived, single-use pairing code containing minimal authority. 3. Require explicit approval through a trusted local interface before exchanging the pairing code for a session. 4. Bind pairing to the expected web origin and validate the origin again for every privileged connector request. 5. Give browser sessions narrowly scoped, rapidly expiring credentials rather than the persistent connector token. 6. Rotate or invalidate the pairing credential immediately after successful use and provide an easy session-revocation mechanism. 7. Apply strict CORS and WebSocket origin validation to the localhost service; do not treat loopback binding as sufficient authentication. 8. Protect against DNS rebinding and cross-site requests by validating the `Host` and `Origin` headers and requiring non-simple authenticated requests. 9. Prevent sensitive values from entering logs, telemetry, diagnostics, browser storage, or Agent transcripts. 10. Document the token lifetime, scope, rotation behavior, and exact connector operations it authorizes. ]]>
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill instructs the agent to perform network-relevant actions such as downloading a connector, generating connection URLs, and opening a browser link, but it declares no explicit tool scope or permissions. This creates a mismatch between stated metadata and actual capability, increasing the chance that an agent executes external-network actions without clear user or platform controls.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger phrases are broad enough to match ordinary user language like 'connect the canvas,' which can cause the skill to activate in situations where the user did not intend to download software, start a local service, or generate authenticated links. Because the skill can lead to execution of local commands and opening URLs carrying connection parameters, accidental invocation meaningfully raises security risk.

Session Persistence

Medium
Category
Rogue Agent
Content
* 用法:node connect.mjs [--canvas https://你的画布域名] [--port 17371] [--source <连接器下载地址或本地文件>] [--sha256 <期望校验值>]
 * 输出(JSON 单行):
 *   { ok:true, url, tokenMasked, pageUrl, alreadyRunning, needStart:false }     连接器已在运行
 *   { ok:false, needStart:true, startCommand:"nohup node … &" }                 需要先启动连接器
 *
 * 安全设计:
 *   - 远程下载必须先通过 SHA-256 校验(官方分发源内置校验值;自定义源必须显式提供 --sha256),校验不符一律拒绝安装;
Confidence
65% 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.

Session Persistence

Medium
Category
Rogue Agent
Content
needStart: true,
        url,
        connectorFile: target,
        startCommand: `nohup node ${target} >> ${join(configDir, "connector.log")} 2>&1 &`,
        hint: "启动后等待约 2 秒,再次运行本脚本即可获得 pageUrl(自动连接链接)",
    }),
);
Confidence
69% confidence
Finding
The script emits a `startCommand` that uses `nohup` and background execution to keep a local connector running persistently after the initiating session ends. In an agent/integration context, this can normalize unattended long-lived local services and may be executed by a caller with limited scrutiny, increasing exposure if the downloaded connector is later abused or replaced.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This markdown file contains user-facing natural-language content entirely in Chinese, but does not indicate that the skill is region-specific or provide any opt-in for language/locale. Under the policy, forcing a specific language without user choice can be a natural-language policy violation.

Natural-Language Policy Violations

Low
Confidence
85% confidence
Finding
All user-facing natural-language instructions and invocation examples are presented only in Chinese, with no indication that another language can be used or that the locale is intentionally restricted. This may violate language/locale policy when the skill is exposed to general users without documented opt-in or region-specific justification.

Static analysis

No suspicious patterns detected.