Back to skill

Security audit

Kie Ai Skill

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly does what it claims, but a credential-handling flaw could send your kie.ai API key to an untrusted image-download URL.

Install only if you are comfortable sending image prompts to kie.ai and storing outputs locally, and avoid using a high-value KIE_API_KEY with this version. The main issue to fix before broad use is removing the Authorization header from image-download requests or enforcing a strict HTTPS host allowlist with redirect validation. Treat any key used with untrusted task results as potentially exposed.

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
lib/generate-image.py:115
Finding
KIE API Key Disclosure Through Unvalidated Image Download URL in Image Generator<![CDATA[ ## Vulnerability Details **File Location**: `lib/generate-image.py:115-160` **Vulnerability Type**: Credential disclosure through an untrusted network destination **Risk Level**: High ### Vulnerable Code ```python result_json_str = data.get("resultJson", "{}") try: result_data = json.loads(result_json_str) images = result_data.get("resultUrls", result_data.get("images", [])) if images: output_dir = Path(__file__).parent.parent / "images" output_dir.mkdir(exist_ok=True) downloaded_paths = [] for i, img_url in enumerate(images, 1): timestamp = time.strftime("%Y-%m-%d-%H-%M-%S") output_path = output_dir / f"{timestamp}-{i}.png" if download_image(img_url, str(output_path)): downloaded_paths.append(str(output_path)) ``` ```python def download_image(url, output_path): """Download image from URL with auth headers""" try: # Try with authorization header first headers = { "Authorization": f"Bearer {API_KEY}", "User-Agent": "Mozilla/5.0" } req = urllib.request.Request(url, headers=headers) with urllib.request.urlopen(req, timeout=30) as response: with open(output_path, 'wb') as f: f.write(response.read()) return True ``` ### Technical Analysis The download URL is obtained from the remotely supplied `resultJson.resultUrls` or `resultJson.images` field. The code does not validate the URL scheme, hostname, port, or relationship to `api.kie.ai` before attaching the user's `KIE_API_KEY` as a bearer token. Consequently, a task response containing an attacker-controlled HTTPS URL causes the Skill to send the API credential directly to the attacker's server. Sending this credential is not necessary for ordinary downloads from public or pre-signed CDN URLs and exceeds the minimum privileges needed for image retrieval. This behavior also contradicts the source ...[truncated 1245 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not attach `KIE_API_KEY` to generated-asset URLs. Attempt downloads without credentials by default. 2. If authenticated downloads are genuinely required, validate the URL before adding the header: - Require `https`. - Use an exact hostname allowlist controlled by the developer. - Reject embedded credentials, unexpected ports, and malformed hostnames. - Do not use suffix-only checks vulnerable to names such as `trusted.example.attacker.test`. 3. Disable redirects or validate every redirect destination before forwarding authorization headers. 4. Keep API authentication requests limited to the fixed `api.kie.ai` origin. 5. Add download limits for response size, content type, and timeout to reduce resource-exhaustion risks. 6. Update the security manifest to document all actual network destinations and authentication behavior. 7. Rotate any KIE API key previously used with affected versions if untrusted task responses may have been processed. A safer baseline is: ```python def download_image(url, output_path): parsed = urllib.parse.urlparse(url) if parsed.scheme != "https": raise ValueError("Only HTTPS image URLs are permitted") req = urllib.request.Request( url, headers={"User-Agent": "kie-ai-skill/1.0"} ) with urllib.request.urlopen(req, timeout=30) as response: with open(output_path, "wb") as f: f.write(response.read()) ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
lib/watch_task.py:49
Finding
KIE API Key Disclosure Through Unvalidated Image Download URL in Task Watcher<![CDATA[ ## Vulnerability Details **File Location**: `lib/watch_task.py:49-61, 111-137` **Vulnerability Type**: Credential disclosure through an untrusted network destination **Risk Level**: High ### Vulnerable Code ```python def download_image(url, output_path): """Download image from URL with auth headers""" try: # Try with authorization header first headers = { "Authorization": f"Bearer {API_KEY}", "User-Agent": "Mozilla/5.0" } req = urllib.request.Request(url, headers=headers) with urllib.request.urlopen(req, timeout=30) as response: with open(output_path, 'wb') as f: f.write(response.read()) return True ``` The untrusted URL reaches this function through the following code: ```python result_json_str = data.get("resultJson", "{}") try: result_data = json.loads(result_json_str) except: result_data = {} images = result_data.get("resultUrls", result_data.get("images", [])) if not images: print("No images generated", file=sys.stderr) return None state_manager.update_task(task_id, "success", {"images": images}) if not download: for url in images: print(f"MEDIA_URL: {url}") return images output_dir = Path(__file__).parent.parent / "images" output_dir.mkdir(exist_ok=True) downloaded_paths = [] for i, img_url in enumerate(images, 1): timestamp = time.strftime("%Y-%m-%d-%H-%M-%S") output_path = output_dir / f"{timestamp}-{i}.png" print(f"Downloading image {i}/{len(images)}...", file=sys.stderr) if download_image(img_url, str(output_path)): downloaded_paths.append(str(output_path)) ``` ### Technical Analysis The watcher accepts image URLs from the remote task record and forwards them to `download_image()` without validating their destination. The function then sends the KIE bearer credential to that remote destination. The remote task response is less trusted than the fixed API origin and m ...[truncated 1347 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `Authorization` header from image-download requests. 2. If the provider requires authenticated asset downloads, permit credentials only for an exact, documented HTTPS hostname allowlist. 3. Prevent authorization headers from being forwarded across redirects; validate each redirect target independently. 4. Separate fixed-origin API requests from asset downloads so generic URLs can never inherit API authentication. 5. Validate returned URLs before storing or displaying them, particularly when `MEDIA_URL` output may be consumed by another agent component. 6. Add maximum response-size and MIME-type checks before writing downloaded content. 7. Add regression tests proving that: - An attacker-controlled URL never receives `KIE_API_KEY`. - Cross-origin redirects do not receive authorization. - Non-HTTPS and non-allowlisted destinations are rejected. 8. Rotate potentially exposed API keys after deploying the corrected implementation. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (34)

Tainted flow: 'req' from os.getenv (line 158, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
req = urllib.request.Request(url, data=req_data, headers=headers, method=method)
    
    try:
        with urllib.request.urlopen(req) as response:
            return json.loads(response.read().decode('utf-8'))
    except urllib.error.HTTPError as e:
        error_body = e.read().decode('utf-8')
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'req' from os.getenv (line 158, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
}
        req = urllib.request.Request(url, headers=headers)
        
        with urllib.request.urlopen(req, timeout=30) as response:
            with open(output_path, 'wb') as f:
                f.write(response.read())
        return True
Confidence
92% confidence
Finding
The code forwards the Bearer API key when downloading image URLs returned by the remote service, but those URLs are not restricted to the trusted kie.ai domain. If the upstream response is compromised or malicious, this will leak the API key to an arbitrary host via the Authorization header, enabling credential theft and possible account abuse.

Tainted flow: 'req' from os.getenv (line 59, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
req = urllib.request.Request(url, headers=headers)
    
    try:
        with urllib.request.urlopen(req) as response:
            result = json.loads(response.read().decode('utf-8'))
            return result
    except urllib.error.HTTPError as e:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'req' from os.getenv (line 59, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
}
        req = urllib.request.Request(url, headers=headers)
        
        with urllib.request.urlopen(req, timeout=30) as response:
            with open(output_path, 'wb') as f:
                f.write(response.read())
        return True
Confidence
90% confidence
Finding
The code forwards the Bearer API key to whatever image URL is returned by the remote service, and on 403 it retries unauthenticated. If the returned URL points to a third-party or attacker-controlled host, the skill will disclose the API key to that host and perform an untrusted outbound fetch.

Credential Access

High
Category
Privilege Escalation
Content
1. **Python 3.6+** (usually pre-installed on macOS/Linux)
2. **kie.ai API Key**:
   - Sign up at https://kie.ai
   - Get API key from dashboard

### Setup
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
1. **Python 3.6+** (usually pre-installed on macOS/Linux)
2. **kie.ai API Key**:
   - Sign up at https://kie.ai
   - Get API key from dashboard

### Setup
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
1. **Python 3.6+** (usually pre-installed on macOS/Linux)
2. **kie.ai API Key**:
   - Sign up at https://kie.ai
   - Get API key from dashboard

### Setup
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The declared purpose emphasizes image generation, but the documentation advertises broader multimodal capabilities including video and music. This mismatch can cause operators or automated policy systems to grant trust or permissions under a narrower assumption than the skill's apparent scope, weakening review and containment.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README explicitly promotes optional Google Drive upload and states that generated files are retained locally and in Drive indefinitely, but it does not clearly warn users that prompts and generated content may contain sensitive data and will persist outside the immediate task context. In an agent skill context, this increases the chance of unintentional data exposure or long-term retention of private material, especially if users assume outputs are ephemeral.

Session Persistence

Medium
Category
Rogue Agent
Content
}
   ```

2. Create symlink:
   ```bash
   ln -s ~/src/kie-ai-skill ~/.openclaw/workspace/skills/kie-ai-skill
   ```
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill declares broad capabilities in practice—environment variable access, filesystem read/write, network access, and shell execution—but does not define any explicit tool scope or permission boundaries. In an agentic environment, that omission increases the chance the skill will be invoked with more authority than necessary, making unintended data access or command execution harder to constrain.

Session Persistence

Medium
Category
Rogue Agent
Content
# Make executable
chmod +x kie-ai.sh lib/*.py

# Create symlink for OpenClaw
ln -s ~/src/kie-ai-skill ~/.openclaw/workspace/skills/kie-ai-skill

# Test it
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The autonomous invocation guidance is broad—an agent may run the skill when asked to generate images—without clear guardrails on confirmation, data sensitivity, or upload behavior. In agent workflows, vague invocation boundaries can lead to unreviewed external transmission of prompts or files and make it easier for downstream prompt injection to trigger actions.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The manifest describes the skill primarily as unified API access for AI models with emphasis on image generation, local storage, Google Drive upload, usage tracking, and task resume. In this file, the help text and models command explicitly present support for video, music, and chat categories, which materially broadens the advertised scope beyond the manifest description.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The config help directs users to unrelated MATON credentials and services even though the skill is branded for kie.ai. This can cause users to expose or misuse third-party credentials, connect the wrong external account, or trust a potentially copied/miswired integration path, which is especially risky in a skill that handles API keys and cloud uploads.

External Transmission

Medium
Category
Data Exfiltration
Content
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% 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
Security manifest:
  Env vars:  KIE_API_KEY (required)
  Endpoints: https://api.kie.ai/api/v1/chat/credit (GET - auth header only, no user data sent)
  File I/O:  reads <skill-root>/.task-state.json (local read only)
  No data is sent to any endpoint other than those listed above.
"""
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.