Back to skill

Security audit

Media.io Text to Video API

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward Media.io text-to-video API wrapper, with expected external API calls and no hidden persistence or unrelated behavior.

Install only if you are comfortable sending prompts and task data to Media.io and using a Media.io API key from the environment. Keep the API key private, avoid placing sensitive information in prompts, and consider hardening the router to disable or explicitly validate redirects before using it with valuable credits.

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/skill_router.py:48
Finding
Media.io API Key May Leak Through Unvalidated Cross-Origin Redirects<![CDATA[ ## Vulnerability Details **File Location**: `scripts/skill_router.py`, lines 48–65 **Vulnerability Type**: Credential disclosure through automatic redirect handling **Risk Level**: Medium ### Vulnerable Code ```python api = self.api_definitions[api_name] url = api['endpoint'] method = api['method'] parsed = urlparse(url) if parsed.scheme != 'https' or parsed.netloc.lower() != 'openapi.media.io': return {'error': f"Blocked endpoint host: {parsed.netloc}"} headers = { 'X-API-KEY': resolved_api_key, 'Content-Type': 'application/json' } if '{' in url: for k, v in params.items(): url = url.replace(f'{{{k}}}', str(v)) body = {k: v for k, v in params.items() if f'{{{k}}}' not in api['endpoint']} try: resp = requests.request(method, url, headers=headers, json={'data': body} if body else {}, timeout=30) ``` ### Technical Analysis The implementation validates the scheme and hostname of the initial endpoint, restricting it to HTTPS requests sent to `openapi.media.io`. However, `requests.request()` follows HTTP redirects by default, and the code does not validate redirect destinations. The credential is transmitted in the custom `X-API-KEY` header. Cross-origin redirect protection commonly associated with the standard `Authorization` header does not reliably protect arbitrary custom authentication headers. Consequently, a redirect to a different origin may cause the API key to be included in the redirected request. The initial endpoint is fixed by the bundled API definition, so exploitation requires the approved Media.io endpoint, its infrastructure, or an upstream component to be compromised or misconfigured so that it returns an attacker-controlled redirect. A redirect status that preserves the HTTP method and body, such as HTTP 307 or 308, could also disclose submitted business parameters. ### Attack Path 1. An attacker compromises or influences `openapi.media.io`, a relevant upstream service, or its redirect configuration. ...[truncated 1286 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Disable automatic redirect handling for authenticated API requests: ```python resp = requests.request( method, url, headers=headers, json={'data': body} if body else {}, timeout=30, allow_redirects=False, ) ``` If redirects are required, implement explicit redirect processing: 1. Inspect each `Location` header without automatically following it. 2. Resolve relative redirects safely against the current URL. 3. Require the destination scheme to remain `https`. 4. Require the normalized destination hostname to equal `openapi.media.io`. 5. Consider restricting redirects to the same origin, including the expected port. 6. Set a small maximum redirect count to prevent loops. 7. Never forward `X-API-KEY` or other sensitive headers when the origin changes. 8. Reject malformed URLs, URLs containing user information, and unexpected ports. 9. Add automated tests covering cross-host 301, 302, 303, 307, and 308 responses and verify that credentials are never sent to an unapproved origin. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (4)

External Transmission

Medium
Category
Data Exfiltration
Content
"description": "API to query user credits balance.",
    "api_header": "{\"list\":[{\"name\":\"X-API-KEY\",\"value\":\"API key to authorize requests\"},{\"name\":\"Content-Type\",\"value\":\"application/json\"}],\"title\":\"Authorizations\",\"describe\":\"Add the following authorization information in the request header\"}",
    "api_body": "{\"title\":\"Request Body\",\"category\":[{\"list\":[],\"title\":\"Query Credits\",\"describe\":\"Request body to query user credits balance\"}]}",
    "api_request_demo": "{\"title\":\"Example Request\",\"request\":[{\"title\":\"Query User Credits\",\"language\":\"cURL\",\"code_example\":\"curl --request POST --url https://openapi.media.io/user/credits --header 'Content-Type: application/json' --header 'X-API-KEY: <api-key>' --data '{}'\"}]}",
    "api_response": "{\"list\":[{\"name\":\"code\",\"type\":\"integer\",\"describe\":\"Response status code, 0 indicates success\"},{\"name\":\"msg\",\"type\":\"string\",\"describe\":\"Response message, empty string on success\"},{\"name\":\"data\",\"type\":\"object\",\"describe\":\"Response data object\"},{\"name\":\"credits\",\"type\":\"integer\",\"describe\":\"User credits balance\"}],\"title\":\"Response\"}",
    "api_code_demo": "{\"list\":[{\"code\":\"0\",\"describe\":\"Success\"}],\"title\":\"Status Code\"}",
    "content": null,
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Low
Confidence
82% confidence
Finding
This JSON manifest-like documentation shows authenticated requests using an `X-API-KEY` header and example cURL commands, but it does not include any warning or note that the API key is sensitive and should be stored or transmitted carefully. For markdown and code this rule is explicit, and for this manifest-style file the omission is still visible in the user-facing skill documentation content.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The documentation instructs users to send an `X-API-KEY` header and provides a full request example, yet there is no accompanying warning that the credential is sensitive. A user-facing note would help prevent accidental exposure in logs, screenshots, or copied commands.

Missing User Warnings

Low
Confidence
85% confidence
Finding
This entry documents a network request that sends user-provided prompt content along with an API key, but the surrounding description does not warn about sensitive credential handling or that submitted content is transmitted to a remote service. That omission reduces user awareness of privacy and credential-safety implications.

Static analysis

No suspicious patterns detected.