Back to skill

Security audit

Grok Imagine Video Generation

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real xAI media-generation integration, but it needs review because its helper code can send the API key to a configurable endpoint and download/write unvalidated remote files.

Install only if you are comfortable sending prompts, media URLs, and generated media requests to xAI. Avoid sensitive or regulated content, keep the xAI key scoped and monitored, do not pass custom API base URLs, and restrict any bot integration so untrusted users cannot choose arbitrary download URLs or output paths.

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/grok_video_api.py:15
Finding

Bearer Credential Disclosure Through an Unvalidated API Base URL

Content
View full analysis

Vulnerability Details

File Location: scripts/grok_video_api.py, lines 15-27 and 51-52; the same authorization behavior is used at lines 81-82, 111-112, 143-144, 176-177, and 211-212.
Vulnerability Type: Credential disclosure through an unvalidated network destination
Risk Level: Medium

Vulnerable Code

python
def __init__(self, api_key: str, base_url: str = "https://api.x.ai/v1"):
    """
    Initialize the client.

    Args:
        api_key: xAI API key from environment or config
        base_url: API base URL (default: https://api.x.ai/v1)
    """
    self.api_key = api_key
    self.base_url = base_url
    self.headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
python
url = f"{self.base_url}/videos/generations"
response = requests.post(url, headers=self.headers, json=payload)

Technical Analysis

The constructor accepts an arbitrary base_url and then creates a reusable authorization header containing the caller's xAI API key. Every authenticated API operation sends that header to a URL derived from the configurable base URL.

The default destination, https://api.x.ai/v1, is appropriate and transmission of the key to xAI is necessary for the declared functionality. However, the implementation does not require HTTPS, validate the hostname, or restrict the destination to xAI. Consequently, any party capable of influencing client construction can redirect authenticated requests to an attacker-controlled server.

The same issue affects video generation, image generation, editing, and job-status requests because all of these methods reuse self.headers.

Attack Path

  1. A victim configures the client with a valid xAI API key.
  2. An attacker influences application configuration, generated integration code, or another input that controls the base_url argument.
  3. The attacker sets base_url to a server under their control, such as `https://attacker. ...[truncated 885 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove public base_url configurability if alternate endpoints are not an explicit functional requirement.
  2. If configurability is required, parse the URL with urllib.parse.urlparse and enforce:
    • The https scheme.
    • An exact hostname allowlist, preferably only api.x.ai.
    • The expected port and API path.
    • No embedded username or password.
  3. Construct the authorization header only after validating the destination.
  4. Revalidate the final request destination after URL composition.
  5. Disable cross-origin redirects for authenticated requests or strip the authorization header whenever a redirect changes the origin.
  6. Avoid retaining the API key in both self.api_key and self.headers unless both copies are required.
  7. Add tests proving that HTTP URLs, lookalike domains, subdomain tricks, embedded credentials, and attacker-controlled hosts are rejected before a request is sent.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/grok_video_api.py:181
Finding

Unrestricted Remote Downloads and Arbitrary Writable-Path File Creation

Content
View full analysis

Vulnerability Details

File Location: scripts/grok_video_api.py, lines 181-195 and 249-267
Vulnerability Type: Unvalidated URL retrieval, unbounded download, and unsafe output-path handling
Risk Level: Medium

Vulnerable Code

python
def download_image(self, image_url: str, output_path: str) -> str:
    """
    Download a generated image file.

    Args:
        image_url: URL of the generated image
        output_path: Local path to save the image

    Returns:
        Path to the downloaded file
    """
    response = requests.get(image_url, stream=True)
    response.raise_for_status()

    os.makedirs(os.path.dirname(output_path), exist_ok=True)

    with open(output_path, "wb") as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)

    return output_path
python
def download_video(self, response_data: Dict[str, Any], output_path: str) -> str:
    """
    Download a completed video file.

    Args:
        response_data: Response from get_job_status (contains video.url)
        output_path: Local path to save the video

    Returns:
        Path to the downloaded file
    """
    video_url = response_data.get("video", {}).get("url")
    if not video_url:
        raise ValueError("No video URL in response")

    response = requests.get(video_url, stream=True)
    response.raise_for_status()

    os.makedirs(os.path.dirname(output_path), exist_ok=True)

    with open(output_path, "wb") as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)

    return output_path

Technical Analysis

Both download helpers perform network requests against caller-controlled or response-derived URLs without validating the scheme, hostname, resolved IP address, redirect destination, content type, or response size. requests follows redirects by default, so an initially acceptable URL can redirect to a disallowed network destination.

If an attacker can inf ...[truncated 2586 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse every media URL and require HTTPS.
  2. Allowlist trusted xAI media hosts where operationally possible.
  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 redirects or validate every redirect target before following it.
  5. Set explicit connection and read timeouts.
  6. Check Content-Length when present and enforce a hard byte limit while streaming, since the header may be absent or dishonest.
  7. Validate the response MIME type against a narrow image or video allowlist.
  8. Restrict output to a dedicated media directory:
    • Resolve the canonical destination path.
    • Confirm it remains beneath the approved directory.
    • Reject traversal and absolute paths supplied by untrusted callers.
    • Reject symlinks or open files using platform-supported no-follow protections.
  9. Use exclusive creation or a controlled overwrite policy rather than silently truncating existing files.
  10. Download to a securely created temporary file, validate the completed content, and atomically move it into place.
  11. Delete partial files when a timeout, size violation, validation failure, or network exception occurs.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (20)

Tainted flow: 'payload' from os.getenv (line 109, credential/environment) → requests.post (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/grok_video_api.py (reported line 60)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

Tainted flow: 'payload' from os.getenv (line 109, credential/environment) → requests.post (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/grok_video_api.py (reported line 89)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

Tainted flow: 'payload' from os.getenv (line 109, credential/environment) → requests.post (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/grok_video_api.py (reported line 115)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

Tainted flow: 'payload' from os.getenv (line 109, credential/environment) → requests.post (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/grok_video_api.py (reported line 147)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

Tainted flow: 'payload' from os.getenv (line 109, credential/environment) → requests.post (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/grok_video_api.py (reported line 179)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

Tainted flow: 'video_url' from os.getenv (line 337, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The code downloads a URL taken from remote response data without validating the destination host or scheme. If the upstream service, configuration, or response is compromised, this can trigger server-side request forgery behavior, unexpected internal network access, or retrieval of maliciously large/untrusted content.

Content

Scanner excerpt · scripts/grok_video_api.py (reported line 274)May include surrounding context.

python
if not video_url:
            raise ValueError("No video URL in response")

        response = requests.get(video_url, stream=True)
        response.raise_for_status()

        os.makedirs(os.path.dirname(output_path), exist_ok=True)

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README promotes bot-integrated image/video generation and editing using external URLs and a third-party API, but it does not warn users that prompts, images, videos, and possibly chat-sourced content will be transmitted to xAI or fetched from external locations. In a messaging-bot context, this omission can cause unintentional disclosure of user content or sensitive media, especially when operators deploy the skill without understanding the privacy and data-flow implications.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 94)May include surrounding context.

OpenClaw Skill Installation

bash
mkdir -p ~/.openclaw/skills
cp grok-imagine-video.skill ~/.openclaw/skills/
cd ~/.openclaw/skills && unzip grok-imagine-video.skill
openclaw gateway restart

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documents and demonstrates code that reads environment variables and makes outbound network requests, but it does not declare an explicit tool scope such as permissions or allowed-tools. That mismatch weakens policy enforcement and reviewability, because a runtime may permit broader capabilities than users or platform controls expect. In this context, the skill’s core purpose legitimately needs env and network access, so the issue is not hidden malicious behavior, but it is still a real least-privilege and transparency problem.

Content

No source excerpt is available for this finding.

Indirect Prompt Extraction

Medium
Category
System Prompt Leakage
Confidence
75% confidence
Finding

Skill contains patterns that could indirectly extract system prompts through rephrasing, translation, summarization, or side-channel techniques.

Content

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

md
- **Unauthorized / API key not set**: → Get your key from https://console.x.ai/ and set `export XAI_API_KEY="your-key"` - See README.md for details
- **Rate limit**: "Too many requests" → Wait and retry
- **Content policy**: "Prompt violates content policies" → Rephrase prompt
- **Timeout**: Job took too long → Reduce duration or complexity

Always wrap API calls in try/except and provide user-friendly messages.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation instructs users to provide source images and videos via public URLs or base64 data without warning that these assets are transmitted to a third-party service and may expose sensitive media or metadata. In a media-generation/editing skill, users are likely to upload personal or proprietary content, so omission of privacy and handling guidance creates a real risk of unintended disclosure.

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 · references/api_reference.md (reported line 9)May include surrounding context.

md
class GrokImagineVideoClient:
    """Client for interacting with xAI Grok Imagine Video API."""

    def __init__(self, api_key: str, base_url: str = "https://api.x.ai/v1"):
        """
        Initialize the client.

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/grok_video_api.py (reported line 17)May include surrounding context.

python
class GrokImagineVideoClient:
    """Client for interacting with xAI Grok Imagine Video API."""

    def __init__(self, api_key: str, base_url: str = "https://api.x.ai/v1"):
        """
        Initialize the client.

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/grok_video_api.py (reported line 23)May include surrounding context.

python
class GrokImagineVideoClient:
    """Client for interacting with xAI Grok Imagine Video API."""

    def __init__(self, api_key: str, base_url: str = "https://api.x.ai/v1"):
        """
        Initialize the client.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/grok_video_api.py (reported line 60)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/grok_video_api.py (reported line 89)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/grok_video_api.py (reported line 115)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/grok_video_api.py (reported line 147)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/grok_video_api.py (reported line 179)May include surrounding context.

python
"resolution": resolution
        }

        response = requests.post(url, headers=self.headers, json=payload)
        response.raise_for_status()
        return response.json()

Static analysis

No suspicious patterns detected.