Back to skill

Security audit

Shortvideo

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real ShortVideo video-generation integration, but it needs Review because it can fetch arbitrary URLs and send credentials or media to an environment-configured server without validation.

Install only if you trust the publisher and can keep SHORTVIDEO_BASE_URL pinned to the legitimate HTTPS ShortVideo API. Do not pass internal, localhost, private-network, or cloud metadata URLs as media inputs. Treat any local files, prompts, product details, and source videos you provide as data that may be uploaded to the configured ShortVideo service, and prefer scoping the API key to this service instead of putting broad secrets in shared shell or agent config files.

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
scripts/impl.py:51
Finding

Environment-controlled API origin can receive bearer credentials and user media

Content
View full analysis
tuple[str, str]: """Get base_url and api_key from environment variables.""" base_url = os.environ.get("SHORTVIDEO_BASE_URL", "") api_key = os.environ.get("SHORTVIDEO_API_KEY", "") if not base_url: print("Error: SHORTVIDEO_BASE_URL environment variable not set") print("Set it with: export SHORTVIDEO_BASE_URL='https://api.shortvideo.ai'") sys.exit(1) if not api_key: print("Error: SHORTVIDEO_API_KEY environment variable not set") print("Please visit https://shortvideo.ai to get your API key") print("Set it with: export SHORTVIDEO_API_KEY='your-api-key'") sys.exit(1) return base_url.rstrip("/"), api_key ``` The environment-controlled origin is then used for authenticated media uploads: ```python def upload_file(filepath: str, upload_type: str = None) -> dict[str, Any]: """Upload a local file to OSS.""" base_url, api_key = get_config() if not os.path.isfile(filepath): return {"status": "error", "error": f"File not found: {filepath}"} file_size = os.path.getsize(filepat ...[truncated 3685 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/product-to-video.py:68
Finding

Unrestricted media URL fetching permits SSRF and external relaying of internal responses

Content
View full analysis
bool: """Check if path is a URL.""" return path and path.startswith(("http://", "https://")) ``` It then fetches that URL without validating the hostname, resolved address, scheme security, or redirects: ```python def download_image_from_url(url: str, timeout: int = 30) -> dict[str, Any]: """Download image from URL to a temporary file.""" try: print(f" Downloading from URL: {url}") response = requests.get(url, timeout=timeout, stream=True) response.raise_for_status() # Check file size content_length = response.headers.get("Content-Length") if content_length and int(content_length) > MAX_FILE_SIZE: return {"status": "error", "error": f"Image too large: {content_length} bytes (max: {MAX_FILE_SIZE})"} # Get extension ext = get_extension_from_url(url) # Create temp file temp_dir = tempfile.gettempdir() filename = f"shortvideo_{uuid.uuid4().hex}{ext}" temp_path = os.path.join(temp_dir, filename) # Download to temp file downloaded_size = 0 with open(temp_path, "wb") as f: for chunk in response.iter_content(chunk_size=8192): if chunk: f.write(chunk) downloaded_size += len(chunk) if downl ...[truncated 3786 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (55)

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

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The script downloads arbitrary user-supplied image URLs with requests.get, which creates a classic SSRF primitive. In the context of an agent skill, a user can cause the runtime to make outbound requests to internal services, cloud metadata endpoints, or other sensitive network locations, and the downloaded response is then processed and uploaded onward.

Content

Scanner excerpt · scripts/image-to-ad-video.py (reported line 118)May include surrounding context.

python
"""
    try:
        print(f"  Downloading from URL: {url}")
        response = requests.get(url, timeout=timeout, stream=True)
        response.raise_for_status()

        # Check content type

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The upload endpoint is also derived from SHORTVIDEO_BASE_URL and receives file contents together with the Authorization token. If the endpoint is redirected to an untrusted server, both uploaded user data and API credentials can be exfiltrated.

Content

Scanner excerpt · scripts/image-to-ad-video.py (reported line 183)May include surrounding context.

python
with open(filepath, "rb") as f:
            files = {"file": (filename, f)}
            data = {"type": upload_type}
            response = requests.post(url, files=files, data=data, headers=headers, timeout=60)
            response.raise_for_status()
            result = response.json()

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The destination for task creation is derived from SHORTVIDEO_BASE_URL and used with an Authorization bearer token. If that environment variable is misconfigured or attacker-controlled, the skill will send API requests and credentials to an arbitrary host, enabling credential exfiltration or unauthorized external transmission.

Content

Scanner excerpt · scripts/image-to-ad-video.py (reported line 228)May include surrounding context.

python
}

    try:
        response = requests.post(url, json=payload, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The video fetch endpoint is built from an environment-controlled base URL and includes the bearer token in the request headers. A malicious or compromised base URL setting would redirect authenticated requests to an attacker-controlled server and expose credentials or job metadata.

Content

Scanner excerpt · scripts/image-to-ad-video.py (reported line 265)May include surrounding context.

python
headers = {"Authorization": f"Bearer {api_key}"}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

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

Critical
Category
Data Flow
Confidence
98% confidence
Finding

This upload path sends local file contents plus the API bearer token to a URL derived from SHORTVIDEO_BASE_URL with no host validation. If the environment variable is tampered with, the skill can exfiltrate arbitrary local files selected for upload directly to an attacker-controlled endpoint, making this especially dangerous in an agent context where local workspace files may contain sensitive data.

Content

Scanner excerpt · scripts/impl.py (reported line 106)May include surrounding context.

python
with open(filepath, "rb") as f:
            files = {"file": (filename, f)}
            data = {"type": upload_type}
            response = requests.post(url, files=files, data=data, headers=headers, timeout=60)
            response.raise_for_status()
            result = response.json()

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

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The request target is derived from SHORTVIDEO_BASE_URL, and the code sends the Authorization bearer token and user-supplied task data to that host without validating the scheme, domain, or allowlist. If an attacker can influence the environment variable, they can redirect requests and exfiltrate API credentials and submitted content to an arbitrary server, which is a real SSRF/credential-leak style issue in agent or CI environments.

Content

Scanner excerpt · scripts/impl.py (reported line 220)May include surrounding context.

python
payload = {"user_id": user_id, "type": task_type, "args": args}

    try:
        response = requests.post(url, json=payload, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

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

Critical
Category
Data Flow
Confidence
96% confidence
Finding

The fetch endpoint URL is built from an untrusted environment-derived base URL and called with the bearer token in the Authorization header. In a hostile runtime, changing SHORTVIDEO_BASE_URL would cause authenticated requests to be sent to an attacker-controlled service, exposing secrets and potentially enabling internal network access patterns.

Content

Scanner excerpt · scripts/impl.py (reported line 262)May include surrounding context.

python
headers = {"Authorization": f"Bearer {api_key}"}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

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

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The script builds the request URL from SHORTVIDEO_BASE_URL, an environment variable, and then sends the bearer API key to that destination in the Authorization header. If an attacker can influence the environment or deployment configuration, they can redirect requests to an attacker-controlled host and exfiltrate the API key, making this a real SSRF/credential-leak risk rather than a harmless configuration issue.

Content

Scanner excerpt · scripts/poll-videos.py (reported line 75)May include surrounding context.

python
headers = {"Authorization": f"Bearer {api_key}"}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

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

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The script accepts a user-supplied --image URL and fetches it directly with requests.get, enabling server-side request forgery if an attacker can influence that argument. In an agent skill context, this is more dangerous because the agent may be induced to access internal services, cloud metadata endpoints, or other sensitive network locations on behalf of the user or runtime environment.

Content

Scanner excerpt · scripts/product-to-video.py (reported line 105)May include surrounding context.

python
"""Download image from URL to a temporary file."""
    try:
        print(f"  Downloading from URL: {url}")
        response = requests.get(url, timeout=timeout, stream=True)
        response.raise_for_status()

        # Check file size

Tainted flow: 'url' from os.environ.get (line 242, 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/product-to-video.py (reported line 164)May include surrounding context.

python
with open(filepath, "rb") as f:
            files = {"file": (filename, f)}
            data = {"type": upload_type}
            response = requests.post(url, files=files, data=data, headers=headers, timeout=60)
            response.raise_for_status()
            result = response.json()

Tainted flow: 'url' from os.environ.get (line 242, 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/product-to-video.py (reported line 209)May include surrounding context.

python
}

    try:
        response = requests.post(url, json=payload, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

Tainted flow: 'url' from os.environ.get (line 242, credential/environment) → requests.get (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/product-to-video.py (reported line 246)May include surrounding context.

python
headers = {"Authorization": f"Bearer {api_key}"}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

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

Critical
Category
Data Flow
Confidence
96% confidence
Finding

The script downloads arbitrary user-supplied URLs with requests.get before uploading them to the ShortVideo service. In an agent skill context this creates an SSRF-style remote fetch primitive that can access internal services, cloud metadata endpoints, or other network locations reachable from the runtime, which is broader than ordinary video-task submission.

Content

Scanner excerpt · scripts/replicate-video.py (reported line 124)May include surrounding context.

python
"""
    try:
        print(f"  Downloading from URL: {url}")
        response = requests.get(url, timeout=timeout, stream=True)
        response.raise_for_status()

        # Check file size

Tainted flow: 'url' from os.environ.get (line 261, 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/replicate-video.py (reported line 183)May include surrounding context.

python
with open(filepath, "rb") as f:
            files = {"file": (filename, f)}
            data = {"type": upload_type}
            response = requests.post(url, files=files, data=data, headers=headers, timeout=120)
            response.raise_for_status()
            result = response.json()

Tainted flow: 'url' from os.environ.get (line 261, 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/replicate-video.py (reported line 228)May include surrounding context.

python
}

    try:
        response = requests.post(url, json=payload, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

Tainted flow: 'url' from os.environ.get (line 261, credential/environment) → requests.get (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/replicate-video.py (reported line 265)May include surrounding context.

python
headers = {"Authorization": f"Bearer {api_key}"}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        result = response.json()

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

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

export SHORTVIDEO_API_KEY="your-api-key-here"

text

Or add to `~/.claude/settings.json`:

```json
{

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says the skill supports three major capabilities: product-to-video, image-to-ad-video, and replicate-video. However, this code chunk is narrowly focused on image-to-ad-video only. The hardcoded task type is 'vidu/image-to-ad-video-v2', the CLI only accepts images plus duration/aspect ratio/prompt, and there is no handling of product metadata/catalog inputs or existing video replication inputs. The network access to ShortVideo API and OSS upload is consistent with the declared domain and is a supporting detail, not an undeclared capability. The mismatch is therefore that the declared purpose is broader than the implemented behavior in the supplied code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code only reads configuration from environment variables, calls a fetch endpoint (/api/video/fetch) with provided video IDs, polls for completion, summarizes statuses, and prints result metadata/URLs. Its primary purpose is monitoring and retrieving results for previously created videos, not generating videos. While this may be part of a larger video workflow, the declared description for this skill specifically emphasizes creation capabilities that are absent from the supplied code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The code’s primary purpose is consistent with one portion of the description—creating product videos via the ShortVideo service—but it does not support the other two prominently declared capabilities: image-to-ad-video and replicate-video. The script contains no handlers, arguments, endpoints, or task types for those modes. Its behavior is therefore materially narrower than the declared description. The URL download, local file upload, OSS upload, and polling logic are supporting implementation details for product-to-video and are not themselves problematic undeclared capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description presents the skill as a broad video-generation capability with three supported functions: product-to-video, image-to-ad-video, and replicate-video. However, the code shown is only for scripts/replicate-video.py and exclusively creates tasks of type vidu/replicate-video. It requires an input video, supports optional product/model images and prompt text, uploads assets, and polls for output videos. There is no code here for generating videos directly from products alone or for creating ad videos from images. The network access to ShortVideo API and file handling are consistent with the declared domain, so the mismatch is not about permissions/resources but about the represented scope and primary supported capabilities. Therefore this chunk does not accurately match the full declared description.

Content

No source excerpt is available for this finding.

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

The skill instructs users to place API credentials in agent-accessible configuration under ~/.claude/settings.json. While not inherently malicious, referencing agent config paths increases the chance that an agent with filesystem access may read or manipulate credential-bearing files, expanding exposure if the broader environment is compromised or if other skills misuse config access.

Content

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

Method 1: Claude Code Config

Add to ~/.claude/settings.json:

json
{

Lp1

High
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The script performs multiple outbound network operations—downloading arbitrary URLs, uploading files, creating tasks, and polling results—without declared network permission coverage. In an agent setting, undeclared network access materially increases risk because the skill can transmit user data or secrets externally without transparent consent.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The script performs multiple outbound network operations—downloading arbitrary URLs, uploading files, creating tasks, and polling results—without declared network permission coverage. In an agent setting, undeclared network access materially increases risk because the skill can transmit user data or secrets externally without transparent consent.

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 3)May include surrounding context.

md
# ShortVideo Skills

Create videos using ShortVideo API with Claude Code / OpenClaw skills.

A collection of Python scripts and Claude Code skills for generating marketing videos, ad videos, and replicating existing videos using the ShortVideo backend API.

Static analysis

No suspicious patterns detected.