Back to skill

Security audit

商品详情图生成 Item Detail

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent ecommerce image-generation tool, but it needs review because it can upload user prompts/images to external providers, fetch arbitrary URLs, and send an Ark API key to a configurable endpoint.

Install only if you are comfortable sending product images, prompts, and brand assets to the selected external generation provider. Prefer local image files or trusted HTTPS image hosts, avoid private/internal URLs, do not use ARK_BASE_URL unless you fully trust the endpoint, and pin or separately review any npm/GitHub tools before installing them.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lib/providers.mjs:23
Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery and Potential Data Exfiltration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lib/providers.mjs:23-43`, `scripts/lib/providers.mjs:147-153`, and `scripts/gen.mjs:218-235` **Vulnerability Type**: Server-Side Request Forgery, unrestricted network access, and unbounded response processing **Risk Level**: High ### Vulnerable Code ```js const isUrl = (s) => /^https?:\/\//i.test(s) const MIME = { '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.webp': 'image/webp', '.gif': 'image/gif', } const mimeOf = (p) => MIME[path.extname(p).toLowerCase()] || 'image/jpeg' async function asBase64(p) { if (isUrl(p)) { const r = await fetch(p) if (!r.ok) throw new Error(`拉取参考图失败 ${r.status}: ${p}`) return Buffer.from(await r.arrayBuffer()).toString('base64') } return (await readFile(p)).toString('base64') } const asDataUri = async (p) => isUrl(p) ? p : `data:${mimeOf(p)};base64,${await asBase64(p)}` ``` The OpenAI provider independently performs the same unrestricted fetch: ```js for (const p of req.images) { const buf = isUrl(p) ? Buffer.from(await (await fetch(p)).arrayBuffer()) : await readFile(p) fd.append('image[]', new Blob([buf], { type: mimeOf(p) }), path.basename(p)) } ``` Provider-returned asset URLs are also fetched without validation: ```js async function persist(files, savePath, req) { if (!files?.length) return [] const out = [] for (const [i, f] of files.entries()) { let target if (savePath) { const ext = path.extname(savePath) || f.ext || '.jpg' const base = savePath.slice(0, savePath.length - path.extname(savePath).length) target = files.length > 1 ? `${base}-${i + 1}${ext}` : `${base}${ext}` } else { target = path.join('output', `${Date.now()}-${i + 1}${f.ext || '.jpg'}`) } await mkdir(path.dirname(target), { recursive: true }) const buf = f.buffer || Buffer.from(await (await fetch(f.url)).arrayBuffer()) await writeFile(target, buf) out.push(target) } ...[truncated 2652 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit HTTPS URLs only unless HTTP access is explicitly required. 2. Resolve the hostname before connecting and reject destinations in: - Loopback ranges - RFC 1918 private ranges - Link-local ranges - Carrier-grade NAT ranges - Multicast and reserved ranges - IPv6 loopback, unique-local, and link-local ranges - Known cloud metadata addresses 3. Repeat destination validation after every redirect to prevent redirect-based bypasses. 4. Prefer an allowlist of trusted image-hosting domains where operationally possible. 5. Require a valid image `Content-Type` and verify the downloaded file signature rather than relying on the URL extension. 6. Enforce strict response-size and download-time limits. Stream responses and abort once the configured maximum is exceeded. 7. Apply the same validation to provider-returned asset URLs in `persist()`. 8. Where possible, configure providers to return image bytes directly rather than arbitrary download URLs. 9. Clearly distinguish local paths from remote URLs and require explicit user consent before fetching remote inputs. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lib/providers.mjs:287
Finding
Configurable Ark Base URL Can Receive API Credentials and User-Supplied Images<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lib/providers.mjs:287-302` **Vulnerability Type**: Credential and sensitive-data disclosure through an unvalidated API endpoint **Risk Level**: High ### Vulnerable Code ```js const ark = { id: 'ark', kind: 'http', hasCredentials: () => Boolean(env.ARK_API_KEY), model: () => env.GEN_MODEL_ARK || env.ARK_MODEL, describe(req) { return `POST ${env.ARK_BASE_URL || 'https://ark.cn-beijing.volces.com/api/v3'}/images/generations model=${ark.model() || '<需设 ARK_MODEL>'}` }, async run(req) { if (!ark.model()) throw new Error('火山方舟需指定模型:export ARK_MODEL=<你开通的 seedream 模型 ID>') const base = env.ARK_BASE_URL || 'https://ark.cn-beijing.volces.com/api/v3' const body = { model: ark.model(), prompt: req.prompt, size: req.size || '2K', response_format: 'url', watermark: false, } if (req.images?.length) body.image = await Promise.all(req.images.map(asDataUri)) const j = await postJson(`${base}/images/generations`, body, { authorization: `Bearer ${env.ARK_API_KEY}` }, req.timeoutMs) return { files: (j.data || []).map((d) => d.b64_json ? { buffer: Buffer.from(d.b64_json, 'base64'), ext: '.jpg' } : { url: d.url, ext: '.jpg' }), raw: j, } }, } ``` ### Technical Analysis `ARK_BASE_URL` completely controls the destination to which the Ark provider sends requests. The value is not restricted to the official Ark hostname, is not required to use HTTPS, and is not checked against a list of trusted endpoints. Every request to this endpoint includes: - `ARK_API_KEY` in a bearer authorization header - The complete user prompt - Model and generation parameters - Local images encoded as data URIs when images are supplied - Remote image URLs in cases where `asDataUri()` preserves the URL This is more dangerous than an ordinary custom endpoint because a production credential is automatically forwarded to whichever dest ...[truncated 1727 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `ARK_BASE_URL` if custom Ark-compatible endpoints are not a required feature. 2. If custom endpoints are required: - Require an explicit command-line opt-in. - Require HTTPS. - Validate the URL before use. - Maintain an allowlist of approved Ark-compatible hostnames. - Reject URLs containing embedded credentials or unexpected ports. 3. Do not automatically send the production `ARK_API_KEY` to a nonofficial hostname. 4. Require a separate credential variable for each custom endpoint. 5. Display the destination hostname and request an explicit confirmation before transmitting images or credentials to a custom service. 6. Document the custom-endpoint data flow and its credential implications. 7. Validate all asset URLs returned by the endpoint before downloading them. 8. Rotate the Ark API key if there is any indication that the process has previously run with an untrusted `ARK_BASE_URL`. ]]>

T08 · Insecure Dependencies

Warning
Location
references/provider-cli.md:64
Finding
Installation Guidance Executes External npm and Repository Content Outside the Audited Package<![CDATA[ ## Vulnerability Details **File Location**: `references/provider-cli.md:64-71`, `scripts/lib/providers.mjs:109-114`, and `scripts/brand.mjs:93-98` **Vulnerability Type**: Unsafe third-party dependency and mutable external code execution **Risk Level**: Medium ### Vulnerable Code and Instructions The provider reference recommends executing a third-party npm package: ```bash npx @dlazy/cli@1.2.3 <command> # 不装全局二进制 ``` ```md - CLI 源码:[github.com/dlazy-ai/cli](https://github.com/dlazy-ai/cli) · npm 包 `@dlazy/cli` ``` The provider implementation recommends an unpinned global installation if the executable is missing: ```js ps.on('error', (e) => { clearTimeout(timer) reject(new Error( e.code === 'ENOENT' ? `找不到 dlazy 命令。装它:npm i -g @dlazy/cli —— 或换后端:PROVIDER=openai|gemini|fal|replicate|ark` : e.message)) }) ``` Brand initialization recommends executing a package installer against a mutable repository URL: ```js if (!existsSync(tpl)) { console.error(`✗ 找不到模板 ${tpl}\n 模板只随 brand-kit 技能分发,装一下:` + `npx skills add https://github.com/dlazy-ai/ecommerce-skills --skill brand-kit`) process.exit(1) } ``` ### Technical Analysis These instructions cause code outside the audited Skill package to be downloaded and executed with the current user’s privileges. The direct `npx` command pins the top-level `@dlazy/cli` version, which reduces version drift, but the audited project provides no lockfile or integrity metadata for its dependency tree. Transitive packages and lifecycle behavior are therefore outside this audit’s trust boundary. The global installation instruction is not version-pinned: ```bash npm i -g @dlazy/cli ``` It consequently installs whichever release currently satisfies npm’s default resolution. The brand installation instruction references a GitHub repository without an immutable commit hash or release tag. Its effective payload can change after this Skill has been reviewed. Depending on the behavior of ...[truncated 1636 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bundle audited functionality directly with the Skill where practical. 2. Replace the unpinned global installation command with an exact, reviewed version. 3. Pin repository-based installation instructions to an immutable commit hash or signed release tag. 4. Publish and verify package integrity hashes or cryptographic signatures. 5. Include a lockfile for all executable dependency trees and review transitive dependencies. 6. Disable npm lifecycle scripts with `--ignore-scripts` when they are not required. 7. Avoid global installation where a restricted local installation is sufficient. 8. Document that external npm and GitHub content falls outside the audited package. 9. Run third-party generation tools in a sandbox with: - Minimal filesystem access - A restricted environment-variable set - No unnecessary provider credentials - Controlled outbound network access 10. Re-audit the exact external CLI release and immutable repository revision before recommending them for production use. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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
Findings (24)

Ae1

High
Category
analysis-evasion
Content
node scripts/gen.mjs --task item-detail \
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/gen.mjs --task item-detail \
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The activation phrases are broad terms like '详情页' and '详情图', which can cause the skill to trigger in situations where the user did not specifically ask for this workflow. Unintended invocation can route user content into image-generation instructions and linked sub-workflows, increasing the chance of confusing behavior, undesired tool use, or data being sent to external model providers.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The description requires generating 带中文排版 and the document repeatedly mandates Chinese text output, but it does not indicate this is optional or user-selectable. That creates a natural-language locale policy issue because the skill forces a specific language by default rather than offering opt-in or documenting a justified region-specific constraint.

Skill Enumeration

Medium
Category
Agent Snooping
Content
| 做法 | 说明 |
| --- | --- |
| ✅ 商品图干净 | 带文字的图会让新排版和旧文字打架,先走 [remove-watermark](https://github.com/dlazy-ai/ecommerce-skills/blob/main/skills/remove-watermark/skill.md) |
| ✅ 卖点写成短句 | `亲肤不扎` 比 `采用优质柔软亲肤面料不刺激皮肤` 好排版 |
| ✅ 文案字数控制 | 主标题 ≤ 8 字,副标题 ≤ 16 字,图标文案 ≤ 5 字 |
| ❌ 一个模块塞十条卖点 | 排不下,会挤成乱码 |
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Skill Enumeration

Medium
Category
Agent Snooping
Content
| 做法 | 说明 |
| --- | --- |
| ✅ 商品图干净 | 带文字的图会让新排版和旧文字打架,先走 [remove-watermark](https://github.com/dlazy-ai/ecommerce-skills/blob/main/skills/remove-watermark/skill.md) |
| ✅ 卖点写成短句 | `亲肤不扎` 比 `采用优质柔软亲肤面料不刺激皮肤` 好排版 |
| ✅ 文案字数控制 | 主标题 ≤ 8 字,副标题 ≤ 16 字,图标文案 ≤ 5 字 |
| ❌ 一个模块塞十条卖点 | 排不下,会挤成乱码 |
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The configuration hard-codes a specific ethnicity ('East Asian woman') for the model, removing user choice and embedding a demographic constraint into a shared brand asset used across multiple skills. This can lead to discriminatory or exclusionary outputs at scale, especially because the file is described as a common source for many SKU-generation workflows.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding
The script prints an installation command using `npx skills add ...` without pinning a specific package version. If a user follows that instruction later, they may execute a newer or compromised package version from the registry, creating a supply-chain risk outside the script's direct logic. In this skill context, that risk is somewhat limited because it is only shown in an error/help path, but it still encourages unsafe installation practices.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script persists provider output to local files via mkdir and writeFile, and even defaults to creating files under an output directory when --save is not supplied. While this behavior is visible in code, there is no confirmation prompt and no explicit user-facing warning near execution that files will be written locally and fetched from remote URLs if needed.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
When a returned file lacks an in-memory buffer, the script fetches f.url and stores the response locally. This is a network operation that may transmit system metadata and retrieve external content, but the non-dry-run path does not provide a specific user-facing disclosure that an outbound fetch will occur.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The helper fetches arbitrary remote URLs from req.images, causing server-side network access based on user-controlled input. That behavior can expose internal network reachability, trigger unexpected outbound requests, and leak request metadata, especially if attackers can supply URLs to internal services or tracking endpoints.

External Transmission

Medium
Category
Data Exfiltration
Content
model: () => env.GEN_MODEL_OPENAI || 'gpt-image-1',
  describe(req) {
    const ep = req.images?.length ? 'images/edits' : 'images/generations'
    return `POST https://api.openai.com/v1/${ep}  model=${openai.model()} size=${mapSize(req.size)} n=${req.batch}`
  },
  async run(req) {
    const key = env.OPENAI_API_KEY
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This code sends user prompts and potentially user-supplied images to third-party model providers, but the file contains no consent, disclosure, or policy gating before transmission. In a skill that may process product assets or private business content, silent exfiltration to external SaaS endpoints creates a real privacy and compliance risk even if the transmission is part of intended functionality.

External Transmission

Medium
Category
Data Exfiltration
Content
: await readFile(p)
        fd.append('image[]', new Blob([buf], { type: mimeOf(p) }), path.basename(p))
      }
      r = await fetch('https://api.openai.com/v1/images/edits', {
        method: 'POST', headers: { authorization: `Bearer ${key}` }, body: fd,
      })
    } else {
Confidence
95% confidence
Finding
This finding duplicates the actual outbound transmission to api.openai.com for image edits. The risk is third-party disclosure of prompt and image data, which is more significant in this skill because product images/descriptions may include unreleased or confidential commercial material.

External Transmission

Medium
Category
Data Exfiltration
Content
: await readFile(p)
        fd.append('image[]', new Blob([buf], { type: mimeOf(p) }), path.basename(p))
      }
      r = await fetch('https://api.openai.com/v1/images/edits', {
        method: 'POST', headers: { authorization: `Bearer ${key}` }, body: fd,
      })
    } else {
Confidence
95% confidence
Finding
This finding duplicates the actual outbound transmission to api.openai.com for image edits. The risk is third-party disclosure of prompt and image data, which is more significant in this skill because product images/descriptions may include unreleased or confidential commercial material.

External Transmission

Medium
Category
Data Exfiltration
Content
method: 'POST', headers: { authorization: `Bearer ${key}` }, body: fd,
      })
    } else {
      r = await fetch('https://api.openai.com/v1/images/generations', {
        method: 'POST',
        headers: { authorization: `Bearer ${key}`, 'content-type': 'application/json' },
        body: JSON.stringify({
Confidence
95% confidence
Finding
This finding duplicates the outbound OpenAI generation request. The main issue is unannounced transmission of user content to a third party, which can create privacy, contractual, or regulatory problems depending on what operators enter into prompts.

External Transmission

Medium
Category
Data Exfiltration
Content
method: 'POST', headers: { authorization: `Bearer ${key}` }, body: fd,
      })
    } else {
      r = await fetch('https://api.openai.com/v1/images/generations', {
        method: 'POST',
        headers: { authorization: `Bearer ${key}`, 'content-type': 'application/json' },
        body: JSON.stringify({
Confidence
95% confidence
Finding
This finding duplicates the outbound OpenAI generation request. The main issue is unannounced transmission of user content to a third party, which can create privacy, contractual, or regulatory problems depending on what operators enter into prompts.

External Transmission

Medium
Category
Data Exfiltration
Content
model: (req) =>
    env.GEN_MODEL_REPLICATE ||
    (req?.images?.length ? 'black-forest-labs/flux-kontext-pro' : 'black-forest-labs/flux-dev'),
  describe(req) { return `POST https://api.replicate.com/v1/models/${replicate.model(req)}/predictions` },
  async run(req) {
    const input = { prompt: req.prompt, num_outputs: req.batch }
    if (req.images?.length) input.input_image = await asDataUri(req.images[0])
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
const input = { prompt: req.prompt, num_outputs: req.batch }
    if (req.images?.length) input.input_image = await asDataUri(req.images[0])
    const j = await postJson(
      `https://api.replicate.com/v1/models/${replicate.model(req)}/predictions`,
      { input },
      { authorization: `Bearer ${env.REPLICATE_API_TOKEN}`, prefer: 'wait' },
      req.timeoutMs,
Confidence
94% confidence
Finding
This call submits prompt content and possibly image data to Replicate's external API. As with the other providers, the issue is not that network use exists at all, but that sensitive user/business content can leave the environment without any visible consent, restriction, or trust-boundary enforcement in this module.

Natural-Language Policy Violations

Medium
Confidence
86% confidence
Finding
The natural-language note at L02 is written only in Chinese and provides no indication that language choice is optional or that the file is intentionally limited to a Chinese-speaking context. Per the policy, forcing a specific language without user opt-in is a natural-language locale violation.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
This file contains user-facing natural language in comments and thrown error strings entirely in Chinese, such as the parser description and later runtime errors. Under the language/locale policy, forcing a specific language without user opt-in or clear justification can be a policy violation.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The thrown errors `YAML: 列表项出现在非列表位置` and `YAML: 看不懂这一行` are user-visible runtime strings in a single language. Because the file does not offer localization or state a region-specific scope, this is a natural-language locale policy issue.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The file's instructional comments and several user-visible error messages are written only in Chinese, which imposes a locale without any opt-in or documented regional requirement. Under the language/locale policy, forcing a specific language is a natural-language policy concern unless the constraint is explicitly justified.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/lib/providers.mjs:104

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/gen.mjs:118

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/lib/providers.mjs:21