Back to skill

Security audit

WayinVideo - AI Clipping

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to be a legitimate video-clipping integration, but it sends user media to a third-party service and has an under-scoped upload path users should review before installing.

Install only if you are comfortable sending selected videos, supported video URLs, and related task metadata to WayinVideo. Avoid using it with confidential recordings, private/internal URLs, or sensitive project names unless the upload destination validation and local result-file handling are tightened. Keep WAYIN_API_KEY scoped to this service and enable system-event polling only when you want host notifications.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/upload_video.py:68
Finding

Unvalidated Remote-Controlled File Upload Destination

Content
View full analysis

Vulnerability Details

File Location: scripts/upload_video.py, lines 68–69 and 88–91
Vulnerability Type: Unvalidated upload URL / sensitive file disclosure
Risk Level: Medium

Vulnerable Code:

python
upload_url = init_data["data"]["upload_url"]
identity = init_data["data"]["identity"]

# ...

with open(file_path, 'rb') as f:
    req = urllib.request.Request(upload_url, data=f, headers=upload_headers, method="PUT")
    req.add_header("Content-Length", str(file_size))
    with urllib.request.urlopen(req) as response:
        if response.getcode() not in (200, 201, 204):
            raise Exception(f"Failed to upload file. Status code: {response.getcode()}")

Technical Analysis

The script obtains upload_url from the WayinVideo API response and uses it directly as the destination for the complete user-selected video. It does not validate the URL scheme, hostname, port, embedded credentials, or redirect destination.

Uploading the selected video is necessary for the Skill's declared clipping functionality. However, trusting a remotely supplied destination without validation exceeds the minimum trust required. If the API response or upstream service is compromised, the response could direct the upload to an attacker-controlled host or an insecure HTTP endpoint.

Because urllib.request.urlopen may follow redirects, validating only the initial URL would also be insufficient unless redirect destinations are restricted.

Attack Path

  1. A user invokes the Skill with a local video.
  2. The script sends an authenticated initialization request to the WayinVideo API.
  3. A compromised API, upstream component, or response path returns a malicious upload_url.
  4. The script accepts the URL without checking its scheme or destination.
  5. The script opens the selected local video and transmits its complete contents using an HTTP PUT.
  6. The attacker-controlled destination receives the vide ...[truncated 943 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse upload_url before opening the local file.
  2. Require the https scheme and reject plaintext HTTP.
  3. Reject embedded usernames or passwords, fragments, unexpected ports, malformed hostnames, and non-public or local-network destinations.
  4. Restrict the hostname to documented WayinVideo-approved storage domains. If dynamic storage providers are required, maintain an explicit and narrowly scoped allowlist.
  5. Disable automatic redirects for the upload or validate every redirect target against the same scheme and hostname policy.
  6. Resolve the destination carefully and block loopback, link-local, private, multicast, and cloud metadata address ranges to reduce DNS-rebinding and internal-network risks.
  7. Fail closed if URL validation cannot establish that the destination is approved.
  8. Consider displaying the validated destination and requesting explicit user confirmation when it differs from the expected provider domain.
  9. Document that local video content is transferred to a third-party service and state the applicable retention policy before upload.
  10. Add automated tests covering HTTP URLs, attacker-controlled hosts, embedded credentials, unexpected ports, redirect chains, DNS rebinding scenarios, and approved presigned storage URLs.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (21)

Tainted flow: 'req' from os.environ.get (line 37, 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/polling_results.py (reported line 38)May include surrounding context.

python
while True:
        try:
            req = urllib.request.Request(url, headers=HEADERS, method="GET")
            with urllib.request.urlopen(req, timeout=30) as response:
                response_text = response.read().decode("utf-8")

                data_res = json.loads(response_text).get("data", {})

Tainted flow: 'req' from os.environ.get (line 26, 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/submit_task.py (reported line 29)May include surrounding context.

python
req = urllib.request.Request(BASE_URL, data=data, headers=HEADERS, method="POST")
    
    try:
        with urllib.request.urlopen(req, timeout=15) as response:
            status = response.getcode()
            response_text = response.read().decode("utf-8")

Tainted flow: 'req' from os.environ.get (line 62, 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/upload_video.py (reported line 63)May include surrounding context.

python
try:
        req = urllib.request.Request(init_url, data=init_payload, headers=init_headers, method="POST")
        with urllib.request.urlopen(req, timeout=30) as response:
            init_data = json.loads(response.read().decode("utf-8"))
        
        upload_url = init_data["data"]["upload_url"]

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The upload destination URL is taken directly from prior API response data and used without validating the hostname or scheme before sending local file contents. If the upstream service, a proxy, or DNS/TLS trust chain were compromised, the script could be induced to upload arbitrary local media to an attacker-controlled endpoint, causing data exfiltration.

Content

Scanner excerpt · scripts/upload_video.py (reported line 87)May include surrounding context.

python
with open(file_path, 'rb') as f:
            req = urllib.request.Request(upload_url, data=f, headers=upload_headers, method="PUT")
            req.add_header("Content-Length", str(file_size))
            with urllib.request.urlopen(req) as response:
                if response.getcode() not in (200, 201, 204):
                    raise Exception(f"Failed to upload file. Status code: {response.getcode()}")

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The manifest presents this as a clipping/highlight skill, but the documented workflow also performs background polling, local file mutation, environment-key handling, and optional system event emission. This mismatch can mislead users and reviewers about what data leaves the system and what local side effects occur, undermining informed consent and safe review.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The manifest presents this as a clipping/highlight skill, but the documented workflow also performs background polling, local file mutation, environment-key handling, and optional system event emission. This mismatch can mislead users and reviewers about what data leaves the system and what local side effects occur, undermining informed consent and safe review.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The workflow explicitly uploads local files or submits URLs to the WayinVideo third-party API, yet the skill description does not prominently warn users that their content may be transmitted off-platform. This is dangerous because users may provide sensitive local videos or private links without understanding the privacy, retention, and disclosure implications.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

python
import urllib.request
import urllib.error

# Get API Key from environment variable
API_KEY = os.environ.get("WAYIN_API_KEY")

if not API_KEY:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/submit_task.py (reported line 9)May include surrounding context.

python
import urllib.request
import urllib.error

# Get API Key from environment variable
API_KEY = os.environ.get("WAYIN_API_KEY")

if not API_KEY:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/upload_video.py (reported line 10)May include surrounding context.

python
import urllib.request
import urllib.error

# Get API Key from environment variable
API_KEY = os.environ.get("WAYIN_API_KEY")

if not API_KEY:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares powerful capabilities including environment access, file read/write, network access, and shell execution, but does not scope or constrain them via an explicit permissions or allowed-tools declaration. That increases the blast radius if the skill is invoked unexpectedly or if downstream scripts behave unsafely, because the agent may have broader access than users realize.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Broad trigger phrasing such as generic 'highlights' or 'best moments' can cause the skill to auto-invoke in situations where the user did not intend to upload media or interact with a third-party service. In this context, overbroad invocation is riskier because the skill can process local files, use an API key, and send data externally.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · assets/platform_duration.md (reported line 1)May include surrounding context.

md
| Platform                | Max Duration (Official)                                                                                              | Recommended Duration (WayinVideo Param)                                      |
| :---------------------- | :------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
| **TikTok**              | Up to **10 min** when recording in-app; up to **60 min** when uploading                                              | `DURATION_0_90` for short-form; `DURATION_180_300` for extended storytelling |
| **Instagram Reels**     | Up to **20 min**                                                                                                     | `DURATION_0_90`                                                              |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · assets/platform_duration.md (reported line 4)May include surrounding context.

md
| Platform                | Max Duration (Official)                                                                                              | Recommended Duration (WayinVideo Param)                                      |
| :---------------------- | :------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
| **TikTok**              | Up to **10 min** when recording in-app; up to **60 min** when uploading                                              | `DURATION_0_90` for short-form; `DURATION_180_300` for extended storytelling |
| **Instagram Reels**     | Up to **20 min**                                                                                                     | `DURATION_0_90`                                                              |
| **YouTube Shorts**      | Up to **3 min**                                                                                                      | `DURATION_0_90` or `DURATION_90_180`                                         |
| **X**                   | Up to **140 sec** for non-Premium; up to **4 hours** on web/iOS for Premium; up to **10 min** on Android for Premium | `DURATION_30_60` or `DURATION_90_180`                                        |
| **Facebook Reels**      | **Facebook now shares all videos as Reels**; no single 90-sec universal cap should be used                           | `DURATION_0_90`                                                              |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · assets/platform_duration.md (reported line 8)May include surrounding context.

md
| Platform                | Max Duration (Official)                                                                                              | Recommended Duration (WayinVideo Param)                                      |
| :---------------------- | :------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
| **TikTok**              | Up to **10 min** when recording in-app; up to **60 min** when uploading                                              | `DURATION_0_90` for short-form; `DURATION_180_300` for extended storytelling |
| **Instagram Reels**     | Up to **20 min**                                                                                                     | `DURATION_0_90`                                                              |
| **YouTube Shorts**      | Up to **3 min**                                                                                                      | `DURATION_0_90` or `DURATION_90_180`                                         |
| **X**                   | Up to **140 sec** for non-Premium; up to **4 hours** on web/iOS for Premium; up to **10 min** on Android for Premium | `DURATION_30_60` or `DURATION_90_180`                                        |
| **Facebook Reels**      | **Facebook now shares all videos as Reels**; no single 90-sec universal cap should be used                           | `DURATION_0_90`                                                              |

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · assets/platform_duration.md (reported line 5)May include surrounding context.

md
| :---------------------- | :------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
| **TikTok**              | Up to **10 min** when recording in-app; up to **60 min** when uploading                                              | `DURATION_0_90` for short-form; `DURATION_180_300` for extended storytelling |
| **Instagram Reels**     | Up to **20 min**                                                                                                     | `DURATION_0_90`                                                              |
| **YouTube Shorts**      | Up to **3 min**                                                                                                      | `DURATION_0_90` or `DURATION_90_180`                                         |
| **X**                   | Up to **140 sec** for non-Premium; up to **4 hours** on web/iOS for Premium; up to **10 min** on Android for Premium | `DURATION_30_60` or `DURATION_90_180`                                        |
| **Facebook Reels**      | **Facebook now shares all videos as Reels**; no single 90-sec universal cap should be used                           | `DURATION_0_90`                                                              |
| **LinkedIn**            | Up to **15 min**                                                                                                     | `DURATION_90_180` or `DURATION_180_300`                                      |

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The polling helper emits system-wide events through an external command, which exceeds the core need of fetching clip-processing results. Because the message content incorporates untrusted API data such as project IDs, status, and file paths, this creates a host-interaction surface that could be abused for social engineering, notification flooding, or misleading operator prompts.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
87% confidence
Finding

The code invokes an external CLI (openclaw system event) and passes dynamic text derived from remote API results and task metadata. Although it uses an argument list rather than a shell, which avoids classic shell injection, it still grants the skill an unnecessary system-wide side-effect channel that can generate deceptive or spammy host notifications based on untrusted remote data.

Content

Scanner excerpt · scripts/polling_results.py (reported line 115)May include surrounding context.

python
def send_system_event(text):
    try:
        subprocess.run([
            "openclaw", "system", "event",
            "--text", text,
            "--mode", "now"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script transmits user-supplied video URLs and associated metadata to an external third-party API, but the disclosure is only implicit in the implementation and skill description rather than enforced at the point of submission. In agent or automation contexts, this can lead to unintended sharing of private media locations, language metadata, project names, or internal URLs without sufficiently explicit user awareness or consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script persists the submitted payload, project ID, endpoint, and submission timestamp to a local JSON file under api_results or a caller-supplied directory. That can expose sensitive operational data such as private video URLs, project names, or translation settings to other local users, backups, logs, or downstream tooling without a strong default warning or data-minimization strategy.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest describes AI-powered highlight extraction and clip generation from URLs or local files, but does not indicate any need for the skill to read secrets from the host environment. Accessing WAYIN_API_KEY is an additional capability related to credential handling rather than the user-facing clipping purpose.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.