Back to skill

Security audit

Openclaw Media Gen

Security checks for vulnerabilities and agentic risk

Overview

This media-generation skill is coherent, but it needs review because it uses an API key and can download unvalidated provider-returned media URLs to local files.

Install only if you trust AIsa with your prompts, reference image URLs, and API key, and run it in a workspace where media downloads cannot overwrite important files. Avoid passing the API key on the command line; use AISA_API_KEY. Treat automatic downloads from generated media URLs as higher risk until the client adds URL allowlisting, private-network blocking, content validation, and size limits.

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

Warning
Location
scripts/media_gen_client.py:114
Finding

Unrestricted Download of Server-Supplied Media URLs

Content
View full analysis
Dict[str, Any]: """ Download a (possibly signed) URL to local file. Designed for OSS signed URLs returned by video generation tasks. """ os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True) req = urllib.request.Request(url, headers={"User-Agent": "AIsa-Media-Gen/1.0"}) try: with urllib.request.urlopen(req, timeout=timeout_s) as resp, open(out_path, "wb") as f: total = 0 while True: chunk = resp.read(1024 * 1024) # 1MB if not chunk: break f.write(chunk) total += len(chunk) return {"success": True, "saved_to": out_path, "bytes": total} except Exception as e: return {"success": False, "error": str(e), "url": url, "saved_to": out_path} ``` Representative server-controlled call sites include: ```python dl = _download_to_file(urls[0], out_path) ``` ```python dl = _download_to_file(url, out_path) ``` ```python video_url = (resp.get("output") or {}).get("video_url") or (resp.get("output") or {}).get("videoUrl") if video_url: out_path = args.out or _safe_filename("mp4") dl = _download_to_file(video_url, out_path) ``` ### Technical Analysis The image and video generation API can return URLs that the client passes directly to `urllib.request.urlopen`. The implementation does not validate: - The URL scheme - The resolved destination address - Whether the destination is loopback, link-local, private, or otherwise reserved - Redirect destinations - The response content type - The maximum response size - Whether the response a ...[truncated 2687 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/media_gen_client.py:62
Finding

API Key Accepted Through a Command-Line Argument

Content
View full analysis
str: api_key = explicit or os.environ.get("AISA_API_KEY") if not api_key: raise ValueError("AISA_API_KEY is required (env or --api-key).") return api_key ``` The parser exposes the corresponding command-line option: ```python p.add_argument("--api-key", help="Override AISA_API_KEY") ``` ### Technical Analysis The client permits users to provide the AIsa credential as `--api-key VALUE`. Command-line arguments are not an appropriate secret transport mechanism because they may be exposed through: - Shell history files - Process inspection utilities - Process-accounting facilities - CI/CD command logs - Agent or terminal telemetry - Debugging and monitoring systems that record process arguments The environment-variable mechanism declared in `SKILL.md` is more appropriate and is sufficient for the Skill's operation. Therefore, the command-line override unnecessarily increases the credential's exposure surface. The code does not print the API key directly, and outbound API requests send it only as a Bearer token to fixed HTTPS AIsa endpoints. The finding concerns local disclosure through argument handling rather than evidence of deliberate credential exfiltration. ### Attack Path 1. A user invokes the client with a command such as `python3 scripts/media_gen_client.py --api-key SECRET image ...`. 2. The shell records the command in its history, or the operating system exposes the argument through process metadata while the client is running. 3. Another local user, monitoring agent, CI log reader, support bundle, or telemetry collector obtains the argument value. 4. The observer reuses the exposed key against the AIsa API. ### Impact ...[truncated 582 chars]
Remediation
View remediation
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 (22)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 96)May include surrounding context.

python
req = urllib.request.Request(url, data=data, headers=all_headers, method=method.upper())
    try:
        with urllib.request.urlopen(req, timeout=timeout_s) as resp:
            raw = resp.read().decode("utf-8")
            return json.loads(raw) if raw else {}
    except urllib.error.HTTPError as e:

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The client downloads arbitrary URLs returned by the remote service and writes the response to a local file without validating the URL scheme, hostname, or response size. If the upstream service is compromised or malicious, it can cause the client to fetch attacker-chosen resources, creating an SSRF-style outbound fetch primitive and potentially downloading untrusted content or very large files to disk.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 122)May include surrounding context.

python
os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
    req = urllib.request.Request(url, headers={"User-Agent": "AIsa-Media-Gen/1.0"})
    try:
        with urllib.request.urlopen(req, timeout=timeout_s) as resp, open(out_path, "wb") as f:
            total = 0
            while True:
                chunk = resp.read(1024 * 1024)  # 1MB

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill requires environment access to AISA_API_KEY and performs outbound network requests, but it does not declare any explicit tool scope such as permissions or allowed-tools. In agent ecosystems, missing scope declarations can cause overbroad execution or unclear operator expectations about what the skill is allowed to access and transmit.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill description and introductory guidance do not clearly warn that user prompts and image URLs are transmitted to external AIsa endpoints. This can lead to unintended disclosure of sensitive text, proprietary prompts, or private image references when users invoke the skill without understanding the data flow.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 163)May include surrounding context.

Documentation: Google Gemini Chat.

bash
curl -X POST "https://api.aisa.one/v1/models/gemini-3-pro-image-preview:generateContent" \
  -H "Authorization: Bearer $AISA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 163)May include surrounding context.

md
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 184)May include surrounding context.

md
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 206)May include surrounding context.

md
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 232)May include surrounding context.

md
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 243)May include surrounding context.

md
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 265)May include surrounding context.

md
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 8)May include surrounding context.

python
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 12)May include surrounding context.

python
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 17)May include surrounding context.

python
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 23)May include surrounding context.

python
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 24)May include surrounding context.

python
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 46)May include surrounding context.

python
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 47)May include surrounding context.

python
Image generation (3 endpoint paths, routed by model):

  gemini-3-pro-image-preview
      POST https://api.aisa.one/v1/models/{model}:generateContent
      Gemini GenerateContent; images arrive as base64 in candidates[].parts[].inline_data.

  wan2.7-image, wan2.7-image-pro

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

Medium
Category
Data Flow
Confidence
90% confidence
Finding

The function writes to an attacker-influenced path via the user-provided --out argument with no path restriction or validation. In agent or automation contexts running with elevated filesystem access, this can overwrite arbitrary files accessible to the process, especially because parent directories are created automatically.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 122)May include surrounding context.

python
os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
    req = urllib.request.Request(url, headers={"User-Agent": "AIsa-Media-Gen/1.0"})
    try:
        with urllib.request.urlopen(req, timeout=timeout_s) as resp, open(out_path, "wb") as f:
            total = 0
            while True:
                chunk = resp.read(1024 * 1024)  # 1MB

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

Medium
Category
Data Flow
Confidence
92% confidence
Finding

This code writes generated image bytes directly to a user-controlled output path. In an interactive CLI this may be expected, but in a hosted agent skill the same behavior can be abused to overwrite arbitrary files within the agent's writable scope, making the skill more dangerous than a normal desktop utility.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 407)May include surrounding context.

python
return 1
        mime, data = images[0]
        out_path = args.out or _safe_filename(_ext_from_mime(mime))
        with open(out_path, "wb") as f:
            f.write(data)
        _print_json({"success": True, "route": route, "model": args.model, "mime_type": mime,
                     "saved_to": out_path, "images_returned": len(images)})

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

Medium
Category
Data Flow
Confidence
92% confidence
Finding

The Seedream b64 response path also writes to a user-specified file location without validation. The risk is arbitrary file overwrite within the process permissions, which is especially relevant for agent skills that may run unattended and process untrusted user input.

Content

Scanner excerpt · scripts/media_gen_client.py (reported line 435)May include surrounding context.

python
kind, data, url = images[0]
        out_path = args.out or _safe_filename("png")
        if kind == "b64" and data is not None:
            with open(out_path, "wb") as f:
                f.write(data)
            _print_json({"success": True, "route": route, "model": args.model,
                         "saved_to": out_path, "images_returned": len(images),

Vague Triggers

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This markdown file includes an activation description, so SQP-1 applies. The phrase 'Use when: the user needs AI image or video generation workflows' is broad and does not define exclusions or trigger constraints, which could cause the skill to match a wide range of ordinary creative requests without clarifying when it should not activate.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.