Back to skill

Security audit

doubao-image

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward Doubao image generator that uses a disclosed Volcengine API key and saves generated images, with manageable privacy and download-safety caveats.

Install only if you are comfortable sending prompts to Volcengine's Doubao API and using a VOLCENGINE_IMAGE_API_KEY in the environment. Avoid prompts containing secrets or regulated personal data, prefer the default workspace output location, and treat downloaded files as untrusted images because the script does not validate URL redirects, file type, or download size.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate.py:132
Finding
Unvalidated Remote Image URL Enables SSRF and Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py`, lines 132–139 **Vulnerability Type**: Server-Side Request Forgery (SSRF), unrestricted download, and unbounded resource consumption **Risk Level**: Medium ### Vulnerable Code ```python def download_image(url, save_path): """下载图片""" try: response = requests.get(url, timeout=60) if response.status_code == 200: with open(save_path, "wb") as f: f.write(response.content) return True ``` ### Technical Analysis The image URL returned in `result["data"][0]["url"]` by the remote generation API is passed directly to `requests.get()` without validating its scheme, hostname, resolved IP address, redirect destination, content type, or response size. The `requests` library follows HTTP redirects by default. Consequently, even an initially acceptable URL could redirect the client to a loopback, link-local, private, or otherwise restricted network address. The response is also fully buffered through `response.content` and written to disk without a size limit. No image signature or MIME-type verification is performed, and every successful response is stored using a `.jpeg` filename regardless of its actual content. Exploitation requires control over, or compromise of, the generation API response or an image-host redirect target. The downloaded request does not include the Volcengine authorization header, limiting direct credential exposure. ### Attack Path 1. An attacker compromises or influences the image-generation API response, causing its `url` field to contain an attacker-selected URL. 2. Alternatively, the returned image URL points to an endpoint that later redirects to an attacker-selected destination. 3. The script passes that URL directly to `requests.get()`, which follows redirects by default. 4. The process requests a local, private-network, link-local, cloud-metadata, or arbitrary Internet endpoint using the network priv ...[truncated 1110 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only HTTPS image URLs. 2. Maintain an explicit allowlist of trusted image-delivery hostnames. 3. Resolve the hostname before connecting and reject loopback, private, link-local, multicast, reserved, and unspecified IP ranges for both IPv4 and IPv6. 4. Disable automatic redirects with `allow_redirects=False`, or validate the scheme, hostname, and resolved address at every redirect hop. 5. Download with `stream=True` and enforce a strict maximum response size using both `Content-Length` and the actual number of streamed bytes. 6. Require an expected image MIME type, such as `image/jpeg` or `image/png`. 7. Validate the downloaded file's signature and decode it with a trusted image parser before accepting it. 8. Write to a temporary file first and atomically move it to the final path only after all validations succeed. 9. Delete partial files when validation or downloading fails. 10. Apply outbound network restrictions at the operating-system or container level so the Skill cannot reach internal services or cloud metadata endpoints. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Tainted flow: 'headers' from os.environ.get (line 67, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
sys.stdout.flush()
        
        try:
            response = requests.post(API_BASE_URL, headers=headers, json=payload, timeout=60)
            
            if response.status_code == 200:
                result = response.json()
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill documents use of environment variables and an external API, which implies access to secrets and network egress, but it does not declare any explicit tool scope such as permissions or allowed-tools. That makes the capability boundary unclear to users and hosts, increasing the risk of over-privileged execution or unexpected secret/network access when the skill is invoked.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill sends user prompts to a third-party image generation service and may return remote image URLs, but the description does not clearly warn users that their input leaves the local environment. This can lead to unintended disclosure of sensitive prompts, metadata exposure through remote URLs, and privacy/compliance issues if users assume the skill is local-only.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The module docstring and user-facing descriptions in this file are presented only in Chinese, which can force a specific language on users without opt-in. The policy allows locale constraints when they are explicitly justified, but no such justification or language choice is provided here.

External Transmission

Medium
Category
Data Exfiltration
Content
sys.stdout.flush()
        
        try:
            response = requests.post(API_BASE_URL, headers=headers, json=payload, timeout=60)
            
            if response.status_code == 200:
                result = response.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Tainted flow: 'save_path' from os.environ.get (line 202, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
try:
        response = requests.get(url, timeout=60)
        if response.status_code == 200:
            with open(save_path, "wb") as f:
                f.write(response.content)
            return True
        else:
Confidence
87% confidence
Finding
The output path is derived from environment variables and then written with open() without constraining it to a trusted base directory. If an attacker can influence OUTPUT_DIR_ENV or OPENCLAW_WORKSPACE, they may cause files to be written to unintended locations, potentially overwriting user-accessible files or placing content in sensitive directories.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
The activation/example language is presented only in Chinese, including the usage phrase '生图:一只可爱的小猫', which can imply a fixed language requirement for invoking the skill. The file does not state that other languages are accepted or explain why a Chinese-only interface is required.

Static analysis

No suspicious patterns detected.