Back to skill

Security audit

卖点主图生成 Item Selling Point

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent e-commerce image generator, but its helper scripts accept arbitrary local file paths and remote URLs as image inputs and can forward that data to external providers.

Review before installing in environments with sensitive local files, internal network access, or confidential product assets. Use only trusted, explicitly selected image files; avoid untrusted image URLs; run dry-runs to inspect destinations; and prefer a sandboxed workspace or patched version that validates image type, size, path containment, and safe public URL destinations.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lib/providers.mjs:33
Finding
Unrestricted Local File Reading and Transmission to External Providers<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lib/providers.mjs:33-43` **Vulnerability Type**: Arbitrary local file disclosure through unrestricted image inputs **Risk Level**: High ### Vulnerable Code ```js 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 same unrestricted file-reading behavior is used by multiple outbound provider implementations, including: - OpenAI: `scripts/lib/providers.mjs:143-155` - Gemini: `scripts/lib/providers.mjs:198-211` - fal: `scripts/lib/providers.mjs:233-240` - Replicate: `scripts/lib/providers.mjs:262-269` - Ark: `scripts/lib/providers.mjs:294-302` ### Technical Analysis The `--images` command-line argument accepts arbitrary strings and passes them to provider implementations without validating that each path identifies an authorized image file. When an input is not recognized as an HTTP or HTTPS URL, `asBase64()` reads the path directly using `readFile()`. There is no enforcement of: - An approved input directory - Canonical path containment - Symbolic-link containment - Allowed file extensions - Image magic bytes - MIME type correctness - Maximum file size - The documented 20 KB to 15 MB limit - The documented JPG, JPEG, PNG, and WebP format restriction The `mimeOf()` helper also defaults unknown extensions to `image/jpeg`. Consequently, a non-image file can be labeled as an image, encoded as a data URI, and included in an outbound request. This behavior exceeds the minimum file-access privileges needed to generate an ecommerce image. The Skill only needs access to product and reference images selected by the user, not every file readable by the executing account. Although transmitting intend ...[truncated 1691 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve every local path to its canonical absolute path before reading it. 2. Restrict image inputs to explicitly approved workspace or media directories. 3. Reject paths whose canonical form escapes the approved roots. 4. Resolve symbolic links and reject links that point outside approved directories. 5. Require explicit user confirmation before reading files outside the project workspace. 6. Allow only the documented JPG, JPEG, PNG, and WebP extensions. 7. Inspect file signatures rather than trusting extensions or supplied MIME types. 8. Decode image metadata and verify that the input is a valid image. 9. Enforce the documented file-size and dimension limits before reading the complete file or making a network request. 10. Reject unknown formats instead of defaulting them to `image/jpeg`. 11. Present the canonical paths and destination provider during dry-run and before upload. 12. Consider accepting opened file handles from a trusted media-selection layer instead of arbitrary path strings. 13. Add tests covering sensitive paths, path traversal, absolute paths, symbolic-link escapes, extension spoofing, and oversized files. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/lib/providers.mjs:23
Finding
Server-Side Request Forgery and External Data Relay Through Unrestricted Image URLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lib/providers.mjs:23-38` **Vulnerability Type**: Server-side request forgery through unrestricted URL fetching **Risk Level**: High ### Vulnerable Code ```js const isUrl = (s) => /^https?:\/\//i.test(s) 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') } ``` OpenAI performs another unrestricted image fetch at `scripts/lib/providers.mjs:147-150`: ```js const buf = isUrl(p) ? Buffer.from(await (await fetch(p)).arrayBuffer()) : await readFile(p) ``` ### Technical Analysis Any string beginning with `http://` or `https://` is treated as a remote image and fetched from the network. The implementation does not apply: - Host or domain allowlisting - DNS resolution checks - Private-address or loopback blocking - Link-local and cloud metadata endpoint blocking - Redirect destination validation - Response content-type verification - Image magic-byte validation - Response-size limits - Explicit timeouts for these GET requests - Streaming limits before buffering the response The process may therefore issue requests to services reachable from its own network position, including localhost, private networks, container networks, and cloud metadata services. For providers that encode downloaded input data, the response is subsequently included in a request to an external generation service. This creates an external data-relay path: information retrieved from an internal endpoint can be sent to OpenAI, Gemini, fal, Replicate, Ark, or another configured provider. Remote image input is useful for the declared functionality, but unrestricted access to all HTTP and HTTPS destinations exceeds the minimum required network privilege. ### Attack Path 1. An attacker controls or influences a value supplied throu ...[truncated 1461 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer local, explicitly selected image files over arbitrary remote URLs. 2. If remote URLs are required, use an allowlist of trusted public image hosts. 3. Require HTTPS unless a narrowly defined exception is explicitly approved. 4. Resolve the hostname before connecting and reject loopback, link-local, private, multicast, unspecified, and reserved addresses for both IPv4 and IPv6. 5. Protect against DNS rebinding by connecting only to the validated resolved address while preserving safe TLS hostname verification. 6. Disable redirects or validate every redirect destination using the same hostname and IP-address controls. 7. Block cloud metadata destinations, including link-local metadata address ranges. 8. Apply strict connection, header, body, and total-operation timeouts. 9. Stream responses with a hard byte limit rather than buffering an unlimited response with `arrayBuffer()`. 10. Require an expected image content type and verify image magic bytes before forwarding data. 11. Decode and validate the image before sending it to a provider. 12. Log the final validated destination without recording credentials or sensitive response content. 13. Add tests covering localhost, private IPv4 and IPv6 ranges, alternate IP representations, redirects, DNS rebinding scenarios, metadata endpoints, oversized bodies, and invalid image responses. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (8)

Vague Triggers

Medium
Confidence
88% confidence
Finding
The skill description includes broad trigger phrases such as '主图', '促销图', and '主图文案', which are common e-commerce terms and can cause the skill to activate for loosely related user requests. This can lead to unintended routing, where the agent invokes this skill in contexts the user did not intend, increasing the chance of inappropriate image-generation actions or mismatched outputs.

Natural-Language Policy Violations

Medium
Confidence
80% confidence
Finding
The skill mandates Chinese copy output in its description and throughout the prompt templates without offering language selection or documenting that it is restricted to a Chinese-language storefront. In a multilingual agent environment, this can cause unintended language-locking, producing unusable or misleading content for users who requested another language or for non-Chinese marketplaces.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The code fetches user-supplied remote image URLs and forwards prompts and image content to third-party providers without any consent gate, disclosure, or restriction in this module. For a skill handling product images and marketing copy, that can expose proprietary images, internal URLs, or sensitive business prompts to external services unexpectedly.

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
88% confidence
Finding
This duplicate finding points to the same OpenAI edit request that transmits image content externally. The risk remains external disclosure of user-provided images and prompts to a third-party service.

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
88% confidence
Finding
This duplicate finding points to the same OpenAI generation request that sends prompt data off-box to a third-party API. The concern is confidentiality and unexpected external processing, not code execution.

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
88% confidence
Finding
This duplicate finding points to the same OpenAI edit request that transmits image content externally. The risk remains external disclosure of user-provided images and prompts to a third-party service.

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
88% confidence
Finding
This duplicate finding points to the same OpenAI generation request that sends prompt data off-box to a third-party API. The concern is confidentiality and unexpected external processing, not code execution.

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
92% confidence
Finding
This call sends prompts and, when present, an input image encoded as a data URI to Replicate's external API. Given the skill's use for product-image generation, transmitting source assets and campaign text to third parties can expose commercially sensitive materials if not clearly disclosed and controlled.

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