Back to skill

Security audit

ai-kujiale-design

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to perform the promised Kujiale interior-design workflow, but it needs review because it handles an access token, uploads local images, and can trigger account-consuming design actions with limited safeguards.

Install only if you trust this publisher and are comfortable connecting your Kujiale account. Use a scoped or short-lived token if possible, keep .kjlconfig.json out of source control, rotate the token after testing, and confirm the exact image file before any upload. Do not let the skill proceed with layout or rendering unless you understand any quota, credit, or account effects.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/searchPlan.js:10
Finding
Access Token Exposure Through Process Arguments and URL Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `scripts/searchPlan.js:10-38` **Additional Locations**: `SKILL.md:23,56,95,101,105,131,146,159,184,189,213,219`; `scripts/createBitmapTask.js:29`; `scripts/createDesign.js:26`; `scripts/getBitmapTaskResult.js:27`; `scripts/getCandidateLayout.js:27`; `scripts/getLayoutResult.js:27`; `scripts/getRenderResult.js:31`; `scripts/getStyles.js:29`; `scripts/getTags.js:25`; `scripts/getUploadToken.js:25`; `scripts/triggerLayout.js:50,62`; `scripts/versionCheck.js:27`; `scripts/trigger-render.js:85,103,127` **Vulnerability Type**: Sensitive credential exposure through command-line arguments and query strings **Risk Level**: Medium ### Vulnerable Code ```javascript const args = process.argv.slice(2); let token = ''; let query = ''; let areaId = ''; let start = '0'; let num = '20'; for (let i = 0; i < args.length; i++) { if (args[i] === '--token' && args[i + 1]) token = args[i + 1]; else if (args[i] === '--query' && args[i + 1]) query = args[i + 1]; else if (args[i] === '--areaId' && args[i + 1]) areaId = args[i + 1]; else if (args[i] === '--start' && args[i + 1]) start = args[i + 1]; else if (args[i] === '--num' && args[i + 1]) num = args[i + 1]; } if (!token) { console.error('Error: --token is required'); process.exit(1); } let path = `/oauth2/openapi/ai-design-skill/floorplan/standard/search?access_token=${encodeURIComponent(token)}&start=${start}&num=${num}`; if (query) path += `&query=${encodeURIComponent(query)}`; if (areaId) path += `&area_id=${areaId}`; const options = { hostname: 'oauth.kujiale.com', port: 443, path: path, method: 'GET' }; ``` The Skill documentation instructs the agent to invoke scripts with the access token directly on the command line, for example: ```text node ./scripts/searchPlan.js --token=<token> --query=<community> --areaId=<city-id> --start=0 --num=20 node ./scripts/trigger-render.js --obsDesignId=<designId> --xToken=<token> ``` ### ...[truncated 2483 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Stop accepting access tokens through command-line arguments. 2. Read the token directly from `.kjlconfig.json` inside each script, or pass it through a protected file descriptor or dedicated secret-injection mechanism. 3. If environment variables are used, ensure the execution platform does not expose them through logs, crash reports, or child-process diagnostics. 4. Send credentials in an HTTP authorization header instead of a URL query parameter, where supported: ```javascript const options = { hostname: 'oauth.kujiale.com', port: 443, path: '/oauth2/openapi/ai-design-skill/floorplan/standard/search', method: 'GET', headers: { Authorization: `Bearer ${token}` } }; ``` 5. If the service requires `access_token` as a query parameter, request or implement a server-side API change. Until then, explicitly redact that parameter from logs, errors, tracing data, and telemetry. 6. Never include complete request URLs containing tokens in exceptions. Construct sanitized diagnostic URLs with credential fields replaced by `[REDACTED]`. 7. Protect `.kjlconfig.json` with owner-only filesystem permissions and document token revocation and rotation procedures. 8. Update every affected script consistently rather than fixing only `searchPlan.js`. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:87
Finding
Shared Inbound Directory Monitoring Can Upload an Unrelated Local Image<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:87-95` **Related Location**: `docs/upload.md:5,27-30` **Vulnerability Type**: Overbroad local-file monitoring and insufficient upload consent **Risk Level**: Medium ### Vulnerable Instruction The Skill instructs the agent to perform the following behavior: ```text Simultaneously monitor ~/.openclaw/media/inbound for new images, checking every five seconds. When an image is detected: 1. Report that an uploaded image was detected. 2. Obtain an upload token. 3. Follow docs/upload.md to upload the image and obtain its URL. ``` The upload documentation also directs the agent to read local file content, calculate its size and MD5 digest, split it when necessary, and upload it to the remote OUS service. ### Technical Analysis The monitored path appears to be a shared inbound-media directory rather than a directory uniquely scoped to the current design task. The instructions do not require the agent to: - Associate the file with the current user message or task identifier. - Confirm the exact detected file path with the user. - Display a preview and obtain explicit consent before transmission. - Ignore files belonging to another session. - Establish a reliable baseline of files that existed before monitoring began. Consequently, any image appearing in the directory during the polling window may be treated as the requested floor plan. Reading a user-supplied floor-plan image and uploading it is necessary for the declared functionality, but continuously watching a shared directory and automatically selecting newly observed content exceeds the minimum file access needed for that function. ### Attack Path 1. The user starts the floor-plan upload workflow. 2. The agent begins polling `~/.openclaw/media/inbound`. 3. An unrelated image enters the directory during the polling period, such as media from another conversation, task, integration, or concurrent user. 4. The Skill identifies that image as th ...[truncated 1104 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove continuous monitoring of the shared inbound-media directory. 2. Require an explicit file attachment or exact local path associated with the current user message. 3. Before uploading, show the user the selected filename or a safe preview and request explicit confirmation that this specific image may be sent to Kujiale. 4. If directory monitoring is unavoidable, create a task-specific directory with a unique, unpredictable identifier and restrict processing to files created for that task. 5. Record a directory baseline before monitoring and reject pre-existing files. 6. Validate ownership, creation time, task/session metadata, file type, and file size before reading the file. 7. Prevent symbolic-link traversal and verify that the resolved canonical path remains within the task-specific upload directory. 8. Process only one explicitly selected image, then stop monitoring immediately. 9. Clearly disclose the destination service and the data transmitted, including image content, filename, size, and MD5 digest. 10. Delete temporary chunks after upload completion or failure and ensure they have restrictive filesystem permissions while present. ]]>
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 (63)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
声明描述的是一个面向用户的室内智能设计 skill,核心能力应是通过对话推进设计流程并最终生成渲染结果。而实际代码仅是一个独立的 CLI 工具:解析 --token、--bitmap、--name 参数,调用 kujiale 的 bitmap/import/async 接口创建异步导入任务。它没有任何对话管理、户型/风格/布局确认逻辑,也没有渲染出图功能。其主要目的与声明的高层产品能力明显不一致,因此应判定为描述与行为不匹配。

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
声明描述的是一个完整的室内设计交互式 skill,核心能力应包括多轮对话引导、设计决策和渲染出图。但提供的代码仅实现了根据 planId 查询户型图信息的网络请求工具,没有任何对话管理、风格/布局处理或渲染逻辑。虽然“户型确认”可能需要获取户型信息,这段代码最多只覆盖了其中一个底层辅助步骤,无法代表声明中的主要功能。因此描述与实际代码行为存在明显不匹配。

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The declared description presents a full interactive interior design skill covering multiple stages: confirming house layout, choosing style, confirming layout, and rendering images. The supplied code only performs one narrow backend action: querying a hard-decoration style library from an external API with a token and optional tag filters. While 'style selection' is related, the code does not implement the broader conversational design workflow or the other claimed stages. Therefore the actual behavior is materially narrower and different from the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description suggests a conversational interior design skill focused on confirming layouts, selecting styles, and generating renderings. The supplied code does none of those things. Instead, it is a utility script for querying custom tags from Kujiale's API using an access token. This is a materially different purpose and involves external API access and token-based data retrieval that are not represented in the description or permissions. Therefore, this is a clear description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
声明描述的是一个面向室内设计的多轮对话式能力,而实际代码只是在调用 oauth.kujiale.com 的接口获取 AI design skill 的上传凭证。这属于明显不同的主要用途:代码没有实现任何室内设计、对话引导、风格选择、布局确认或渲染逻辑,反而执行了与认证/上传准备相关的网络访问。该行为更像是支持性运维/接口调试工具,而不是所声明的终端 skill 功能,因此存在明显描述与行为不一致。

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
声明描述的是一个面向用户的室内智能设计 skill,核心能力应包含交互式流程推进以及设计/渲染相关功能。但给出的代码仅实现了一个独立的搜索户型脚本:解析命令行参数,向 kujiale 的 floorplan search 接口发起 GET 请求,并输出返回结果。它没有实现对话式流程控制,也没有风格选择、布局确认或渲染出图逻辑。虽然“户型确认”可能与户型搜索存在弱相关,但该代码的主要目的与声明的整体功能相比明显更窄且不同,因此构成描述与实际行为不匹配。

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
声明描述的是一个面向用户的“室内智能设计”对话式 skill,核心流程应包括户型确认、风格选择、布局确认以及最终渲染出图。但提供的代码并不包含任何对话管理、用户输入收集、户型/风格/布局决策逻辑。它的实际作用仅是基于已存在的 obsDesignId,调用外部接口触发自动视角生成并提交渲染任务,属于渲染流水线中的技术性后处理脚本。虽然“渲染出图”与声明的最后一步部分相关,但代码覆盖的功能范围明显更窄,且主要能力与声明的核心交互式设计流程不符。此外,代码显式依赖 xToken 进行鉴权并访问多个外部 API,这种关键能力/资源访问也未在声明中体现。因此应判定为描述与实际行为不匹配。

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents an end-user interior design conversational workflow focused on confirming room layout, selecting style, confirming arrangement, and generating renders. The supplied code does not implement any conversational design flow, rendering, layout handling, or style selection. Instead, it performs a backend/administrative version-check operation against an external API using an access token and version parameter. This is a materially different primary purpose and involves undeclared external resource access unrelated to the described design interaction.

Ae1

High
Category
analysis-evasion
Content
每次执行前调用:`node ./scripts/versionCheck.js --token=${token} --version=0.0.6`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/searchPlan.js --token=<token> --query=<小区名> --areaId=<城市id> --start=0 --num=20
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/getUploadToken.js --token=<token>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/createBitmapTask.js --token=<token> --bitmap=<url>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/getBitmapTaskResult.js --token=<token> --taskId=<taskId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/createDesign.js --token=<token> --planId=<planId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/getTags.js --token=<token>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/getStyles.js --token=<token> --tagItemIds=<id1,id2,...>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/triggerLayout.js --token=<token> --designId=<designId> --tagIds=<id1,id2,...> --styleId=<styleId> --applyDecorationStyle=true --buildCeiling=true
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/getLayoutResult.js --token=<token> --designId=<designId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/trigger-render.js --obsDesignId=<designId> --xToken=<token>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node ./scripts/getRenderResult.js --token=<token> --designId=<designId>
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill clearly instructs networked API use, token handling, uploads, polling, and rendering, but it declares no explicit tool scope or allowed-tools. Missing scope declarations weaken least-privilege controls and make it easier for an agent runtime to grant broader capabilities than users or reviewers expect.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs users to place an access token in a local JSON file at the project root without any guidance on file permissions, secret management, or exclusion from source control. This can easily lead to credential leakage through local compromise, accidental commits, backups, logs, or shared workspaces.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill instructs continuous monitoring of a local inbound media directory for new images without clearly informing the user that local files are being watched and may be processed automatically. This undermines user awareness and can unintentionally ingest unrelated sensitive images placed in that directory by other workflows.

Ssd 3

Medium
Confidence
94% confidence
Finding
Continuous polling of a local inbound directory creates an implicit data collection channel outside the immediate chat interaction. In a skill that handles user images and uploads them to remote services, this broadens data exposure and increases the chance of collecting or transmitting unintended content.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The workflow says the user must confirm they understand quota or credit consumption before layout generation, but the documented flow proceeds directly into layout generation. This creates a consent bypass that can trigger billable or irreversible actions without an explicit authorization checkpoint.

Static analysis

No suspicious patterns detected.