Back to skill

Security audit

lanhu-design

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent Lanhu design-download purpose, but it handles browser-session credentials and downloaded manifests too broadly, creating real exposure risk for private Lanhu data and local files.

Review before installing. Use this only with Lanhu projects and slice JSON you trust, avoid running it in workspaces with sensitive local files, keep LANHU_COOKIE short-lived and never commit it, and open generated HTML previews in a constrained browser context. The publisher should add strict URL allowlists, remove file:// manifest support, avoid sending cookies to asset URLs, validate redirects and response sizes, and safely serialize generated HTML/CSS.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lanhu-client.mjs:33
Finding

Lanhu Session Cookie Is Forwarded to Unvalidated Resource Hosts

Content
View full analysis
controller.abort(), HTTP_TIMEOUT); try { const response = await fetch(url, { ...options, signal: controller.signal, headers: { ...HEADERS, Cookie: getCookie(), ...options.headers }, redirect: "follow", }); if (response.status === 401 || response.status === 403) { throw new Error( `认证失败 (HTTP ${response.status})。LANHU_COOKIE 可能已过期,请重新获取。`, ); } if (!response.ok) { throw new Error(`HTTP ${response.status} ${response.statusText}`); } return response; } finally { clearTimeout(timeout); } } ``` An API-provided URL is passed directly to the authenticated request function: ```js const sketchData = await requestJson(latestVersion.json_url); ``` The same issue exists in the shared file downloader: ```js export async function downloadFile(url, localPath, referer) { await mkdir(path.dirname(localPath), { recursive: true }); const headers = {}; if (referer) headers.Referer = referer; const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), HTTP_TIMEOUT); try { const response = await fetch(url, { headers: { ...HEADERS, Cookie: getCookie(), ...headers }, signal: controller.signal, redirect: "follow", }); if (!response.ok) { throw new Error(`HTTP ${response.status} ${response.statusText}`); } const buffer = Buffer.from(await response.arrayBuffer()); await writeFile(localPath, buffer); } finally { clearTimeout(timeout); } } ``` ### Technical Analysis `LANH ...[truncated 1962 chars]
Remediation
View remediation

other

Error
Location
scripts/download_slices.mjs:199
Finding

Arbitrary URL Fetching in Slice Manifests Enables SSRF

Content
View full analysis
controller.abort(), 30_000); try { const headers = { "User-Agent": "Mozilla/5.0" }; if (referer) headers.Referer = referer; const response = await fetch(url, { headers, signal: controller.signal }); if (!response.ok) { throw new Error(`HTTP ${response.status} ${response.statusText}`); } return Buffer.from(await response.arrayBuffer()); } finally { clearTimeout(timeout); } } ``` ### Technical Analysis The downloader treats `scale_urls` and `download_url` values from an input JSON document as trusted network destinations. It performs no validation of: - URL scheme - Destination hostname - Destination port - Resolved IP address - Redirect destinations - Loopback, private, link-local, or reserved networks - Response content type - Response size Because the Skill's documented workflow directs the Agent to save slice metadata as JSON and then pass it to this script, malicious or tampered metadata can cause requests to arbitrary services reachable from the Agent's execution environment. ### Attack Path 1. An attacker supplies or influences a slice JSON document. 2. A slice contains a URL such as: - `http://127.0.0.1:8080/admin` - `http://169.254.169.254/latest/meta-data/` - A pr ...[truncated 979 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/download_slices.mjs:199
Finding

Slice Manifests Can Copy Arbitrary Local Files into Project Assets

Content
View full analysis
controller.abort(), 30_000); try { const headers = { "User-Agent": "Mozilla/5.0" }; if (referer) headers.Referer = referer; const response = await fetch(url, { headers, signal: controller.signal }); if (!response.ok) { throw new Error(`HTTP ${response.status} ${response.statusText}`); } return Buffer.from(await response.arrayBuffer()); } finally { clearTimeout(timeout); } } ``` ```js async function download(url, outputPath, referer, retries) { await mkdir(path.dirname(outputPath), { recursive: true }); let lastError = null; for (let attempt = 0; attempt <= retries; attempt += 1) { try { await writeFile(outputPath, await fetchBuffer(url, referer)); return; } catch (error) { lastError = error; if (attempt < retries) await delay(500 * (attempt + 1)); } } throw lastError; } ``` ### Technical Analysis Supporting `file://` is not necessary for the declared function of downloading Lanhu-hosted design slices. A manifest can point to any local file readable by the Node.js process. The contents are then copied into the selected output directory under an apparently ordinary image filename. Filename sanitization does not mitigate this issue because the vulnerability concerns the source path rather than destination path traversal. This crosses the minimum-privilege boundary of the Skill: design asset retrieval should not read unrelated host files. ### Attack Path 1. An attacker creates or modifies a slice mani ...[truncated 1048 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/design-converter.mjs:273
Finding

Untrusted DDS Schema Values Can Inject Active Content into Generated HTML

Content
View full analysis
`rgba(${r}, ${g}, ${b}, ${a.includes(".") ? parseFloat(a) : parseInt(a, 10)})` ); } if (/^\d+$/.test(value) && !UNITLESS_PROPERTIES.has(key)) { return value === "0" ? "0" : `${value}px`; } } return String(value); } ``` ```js function generateCss(node, cssRules, loopSuffixes = null) { if (!node) return; let suffixes = loopSuffixes; const loopArr = node.loopType ? getLoopArr(node) : []; if (loopArr.length && !suffixes) suffixes = loopArr.map((_,i) => String(i)); const nodeProps = node.props || {}; const className = nodeProps.className; if (className) { const flexCls = getFlexClasses(node); const styles = cleanStyles(node, flexCls); const entries = Object.entries(styles); let content = ""; if (entries.length || node.type === "lanhutext") { content = entries .map(([k,v]) => { const val = formatCssValue(k,v); return val ? ` ${camelToKebab(k)}: ${val};` : null; }) .filter(Boolean).join("\n"); } if (suffixes) { for (const suf of suffixes) cssRules[`${className}-${suf}`] = content; } else { cssRules[className] = content; } } for (const child of node.children || []) { generateCss(child, cssRules ...[truncated 2716 chars]
Remediation
View remediation
`, null bytes, control characters, or case-insensitive `` variants, and control-character variants. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (18)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/download_design_images.mjs` | 下载设计图原图到本地目录(视觉校验用) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/download_design_images.mjs` | 下载设计图原图到本地目录(视觉校验用) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/download_slices.mjs` | 从切图 JSON 批量下载切图文件 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/download_slices.mjs` | 从切图 JSON 批量下载切图文件 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/download_slices.mjs` | 从切图 JSON 批量下载切图文件 |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/lanhu-client.mjs` | 共享 HTTP 客户端模块(被上述脚本引用,不直接运行) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/design-converter.mjs` | 纯转换模块(被 get_design_specs.mjs 引用,不直接运行) |

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill instructs the agent to use environment credentials (LANHU_COOKIE) and make authenticated network requests, but it declares no explicit tool scope or permission boundary. That creates an over-privileged integration surface where an agent may access sensitive session cookies and external endpoints without clear policy constraints, increasing the risk of credential misuse, unintended data exfiltration, or execution in contexts that did not intend to allow networked authenticated actions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The entire skill reference is written as mandatory operational guidance in Chinese and does not offer any user opt-in for language or locale. Under the stated policy, forcing a specific language without user choice is a natural-language policy violation unless the locale restriction is clearly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code fetches remote content from URLs in the input JSON and writes the results to disk, including optional transmission of a Referer header. While the script logs success and failure after the fact, it does not warn users up front that it will contact remote hosts and create files in the specified output directory.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code reads a session cookie from the LANHU_COOKIE environment variable and attaches it to outbound HTTP requests, which is a sensitive credential-handling operation. There is no confirmation prompt, logging, comment-based warning, or other user-facing disclosure near the request path to make clear that authenticated session data will be sent to remote services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

downloadFile writes attacker-controlled remote content to an arbitrary localPath with no path validation, extension/type checks, size limits, or destination restrictions. In an agent skill context, this can enable overwriting files or dropping untrusted content into sensitive locations if an upstream caller passes a malicious path or URL.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The converter hardcodes <html lang="en"> in generated output, which imposes a specific locale on all converted documents. This is a natural-language locale policy issue because the file does not offer user opt-in or explain why English is required.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

This second HTML generation path also emits <html lang="en"> unconditionally. Because no language selection or justification is provided, it enforces an English locale across outputs in a way that may violate language-choice policy.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script’s user-facing help text is written in Chinese, and additional runtime messages elsewhere in the file are also Chinese-only. For a general-purpose CLI, this imposes a specific language on users without any opt-in or explanation that the tool is intended only for a Chinese-speaking context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This code invokes getDesignSlicesInfo(url, designName, includeMetadata), which by name and inputs appears to contact an external Lanhu service using a user-supplied project URL. The script provides usage examples but does not explicitly disclose that it will make a network request or transmit project-identifying data, and there is no confirmation prompt or user-facing notice beyond the raw output.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The CLI usage text includes a Chinese-only example string, which can be interpreted as forcing or privileging a specific language in user-facing output. The policy requires avoiding language constraints unless the user is given a choice or the locale is clearly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file's user-facing error/help text is written in Chinese, and similar strings throughout the module continue that language choice without any opt-in or localization option. This can violate language/locale policy when a skill unconditionally forces a specific language for users.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.