Back to skill

Security audit

Media Gen

Security checks for vulnerabilities and agentic risk

Overview

This media-generation skill is mostly purpose-aligned, but it needs review because its helper script can download unvalidated API-provided URLs and write outputs to arbitrary local paths.

Install only if you are comfortable sending prompts, reference image URLs, task IDs, and an AIsa API key to AIsa. Prefer setting the key with AISA_API_KEY rather than --api-key, use non-sensitive prompts and image URLs, run it in a workspace with limited file permissions, and choose output paths carefully because existing files can be overwritten.

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:107
Finding

Unvalidated API-Provided URLs Permit Arbitrary Resource Downloads

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} ``` API-provided URLs reach this function without validation: ```python dl = _download_to_file(urls[0], out_path) ``` ```python if kind == "url" and url: 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 client treats media URLs returned by the remote API as trusted and passes them directly to `urllib.request.urlopen`. It does not validate: - The URL scheme - The destination hostname - The resolved IP address - Whether the destination is loopback, private, link-local, or otherwise reserv ...[truncated 2132 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/media_gen_client.py:55
Finding

API Key May Be Exposed Through Command-Line Arguments

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 a command-line option for the credential: ```python p = argparse.ArgumentParser(description="Media Gen - image & video generation") p.add_argument("--api-key", help="Override AISA_API_KEY") ``` ### Technical Analysis The client supports supplying the AIsa credential through `--api-key`. Command-line arguments are commonly visible in shell history, process inspection tools, terminal capture, job-runner telemetry, debugging output, and audit logs. Although the documented quick start recommends `AISA_API_KEY`, the command-line option remains available and the error message explicitly advertises it. Passing long-lived secrets through process arguments is unnecessary because the Skill already supports an environment variable. The API key is otherwise transmitted as a Bearer token only to fixed HTTPS AIsa API endpoints. Download requests do not include it, and no hardcoded credential was found. ### Attack Path 1. A user invokes the client with an argument such as `--api-key `. 2. The shell records the command in history, or the operating system exposes the argument through process-inspection facilities. 3. A local user, administrator, monitoring agent, CI log consumer, or telemetry operator reads the recorded command line. 4. The observer extracts the AIsa API key and uses it against the AIsa service. The exact visibility of process arguments depends on operating-system controls and local account isolation. ### Impact Assessment Disclos ...[truncated 382 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (21)

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
91% confidence
Finding

The client downloads arbitrary URLs returned by the remote API, or supplied indirectly through task status responses, without validating scheme, host, redirect targets, content type, or size. If the upstream service is compromised or returns attacker-controlled signed URLs, this can be abused for SSRF-like access from the local machine or for downloading very large/unexpected content 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
95% confidence
Finding

The skill requires environment access to AISA_API_KEY and makes outbound network requests, but it does not declare any explicit tool scope such as permissions or allowed-tools. That omission weakens least-privilege controls and may cause agents or users to invoke a networked, secret-using skill without clear upfront authorization boundaries.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill instructs users to send prompts and, for image-to-video, image URLs to an external third-party API, but it does not prominently warn that user content and metadata will leave the local environment. This creates privacy and compliance risk because users may submit sensitive prompts, proprietary images, or internal URLs without realizing they are being transmitted off-platform.

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 161)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 161)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 180)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 201)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 225)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 236)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 257)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
89% confidence
Finding

The function writes downloaded content to an arbitrary path provided via --out, creating parent directories as needed, with no path restriction or overwrite protection. In an agent context, if an untrusted user can influence --out, the skill can overwrite files accessible to the process, which may lead to data loss or clobbering important local files.

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
90% confidence
Finding

This code writes generated image bytes directly to a caller-controlled output path without validating where that path points. In a tool/agent setting, that enables arbitrary file write within the permissions of the running process if a user or chained workflow can supply --out.

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
90% confidence
Finding

Like the other image-save path, this branch writes base64-decoded content to an unvalidated output path controlled by --out. The risk is arbitrary file overwrite/clobbering on the local system when the skill is invoked with attacker-influenced arguments.

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),

Static analysis

No suspicious patterns detected.