Back to skill

Security audit

URL to Video Generator

Security checks for vulnerabilities and agentic risk

Overview

The skill is not overtly malicious, but it needs review because it fetches websites, downloads packages/media, and writes generated project files with weak scoping and unsafe input handling.

Install or run this only in a restricted workspace with minimal credentials and network access. Use only public, non-sensitive website URLs; validate brand names as simple slugs before running the scaffold script; review generated files before npm install/build; and prefer pinned dependencies, a lockfile, and local Remotion binaries instead of npx-fetched commands.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/extract_colors.py:11
Finding
Unvalidated Website Fetch Enables Server-Side Request Forgery and Unbounded Response Consumption<![CDATA[ ## Vulnerability Details **File Location**: `scripts/extract_colors.py`, lines 11–21 and 57–64 **Vulnerability Type**: Server-Side Request Forgery and uncontrolled resource consumption **Risk Level**: High ### Vulnerable Code ```python def extract_colors(url): """Extract hex and rgb colors from website CSS/HTML.""" try: req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'}) with urllib.request.urlopen(req, timeout=15) as response: html = response.read().decode('utf-8', errors='ignore') except Exception as e: print(f"Error fetching {url}: {e}") sys.exit(1) ``` ```python def main(): if len(sys.argv) < 2: print("Usage: python extract_colors.py <website_url>") sys.exit(1) url = sys.argv[1] if not url.startswith('http'): url = 'https://' + url print(f"Extracting colors from {url}...\n") colors, rgb_colors = extract_colors(url) ``` ### Technical Analysis The script accepts an arbitrary URL and passes it directly to `urllib.request.urlopen`. It does not strictly validate the URL scheme, resolve and inspect the destination address, reject private or reserved networks, or validate the destination again after an HTTP redirect. Consequently, an attacker who can control the script argument can cause requests to loopback addresses, link-local services, private network hosts, or other endpoints reachable from the execution environment. Public endpoints that redirect to internal addresses can also bypass checks because redirect targets are not inspected. The call to `response.read()` reads the complete response into memory. The 15-second timeout limits waiting time but does not impose a maximum response size. A remote server can therefore return an excessively large or continuously streamed response and cause significant memory consumption. ### Attack Path 1. An attacker supplies a URL such as an internal HTTP service, loopback endpoint, o ...[truncated 1256 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse URLs with `urllib.parse.urlsplit` and allow only exact `http` and `https` schemes. 2. Reject URLs containing credentials or malformed hostnames. 3. Resolve every hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, and reserved IPv4/IPv6 addresses using Python's `ipaddress` module. 4. Disable automatic redirects or validate every redirect target with the same policy. 5. Defend against DNS rebinding by ensuring the validated resolved address is the address actually used for the connection. 6. Use a strict allowlist when the expected set of target domains is known. 7. Read responses incrementally and abort after a defined limit, such as 5–10 MB. 8. Limit redirect count, enforce connection/read timeouts, and verify that the response content type is appropriate HTML or CSS. 9. Run website-fetching logic in a restricted network sandbox without access to internal services or cloud metadata endpoints. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/init-project.sh:6
Finding
Unvalidated Brand Name Enables Directory Traversal and Generated-File Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/init-project.sh`, lines 6–17, 20–37, and 60–72 **Vulnerability Type**: Path traversal and generated JSON/TypeScript injection **Risk Level**: High ### Vulnerable Code ```bash BRAND=$1 URL=$2 if [ -z "$BRAND" ] || [ -z "$URL" ]; then echo "Usage: ./init-project.sh <brand-name> <website-url>" echo "Example: ./init-project.sh futurai https://futurai.org" exit 1 fi PROJECT="remotion-${BRAND}-promo" echo "Creating project: $PROJECT" mkdir -p "$PROJECT"/{src,audio,out,stills} cd "$PROJECT" ``` ```bash cat > package.json << EOF { "name": "$PROJECT", "version": "1.0.0", "scripts": { "start": "remotion studio", "build": "remotion render src/index.tsx ${BRAND}-promo out/video.mp4", "stills": "remotion still src/index.tsx ${BRAND}-promo" }, "dependencies": { "@remotion/cli": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "remotion": "^4.0.0" }, "devDependencies": { "@types/react": "^18.2.0", "typescript": "^5.0.0" } } EOF ``` ```bash cat > src/index.tsx << EOF import { registerRoot, Composition } from 'remotion'; import { ${BRAND^}Promo } from './${BRAND^}Promo'; registerRoot(() => ( <Composition id="${BRAND}-promo" component={${BRAND^}Promo} durationInFrames={1440} fps={24} width={854} height={480} /> )); EOF ``` ### Technical Analysis The `BRAND` parameter is accepted without character, length, path, or identifier validation. It is used in three different security-sensitive contexts: 1. **Filesystem path construction:** `PROJECT="remotion-${BRAND}-promo"` 2. **JSON generation:** values and npm script commands in `package.json` 3. **TypeScript generation:** imports, identifiers, and string literals in `src/index.tsx` Shell quoting around `"$PROJECT"` prevents ordinary shell word splitting, but it does not make a path containing `/` or `..` safe. A crafted brand can introduce path components that cause ...[truncated 2249 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict `BRAND` to a conservative slug: ```bash if [[ ! "$BRAND" =~ ^[a-z0-9][a-z0-9-]{0,62}$ ]]; then echo "Invalid brand name" >&2 exit 1 fi ``` 2. Reject `/`, `\`, `..`, control characters, whitespace, quotes, and shell/source-language metacharacters. 3. Resolve the final project path with `realpath` and verify that it remains under an explicitly selected base directory. 4. Refuse to overwrite an existing destination unless the operator explicitly requests it. 5. Generate `package.json` using a JSON-aware tool or serializer rather than an interpolated heredoc. 6. Derive a separate PascalCase TypeScript identifier from the validated slug and validate it against TypeScript identifier rules. 7. Pass dynamic values into source templates through a safe templating mechanism with context-specific escaping. 8. Avoid embedding user input directly into npm command strings. 9. Create files with restrictive permissions and use atomic, no-clobber writes where practical. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/init-project.sh:20
Finding
Mutable npm Dependency Versions Create a Supply-Chain Exposure<![CDATA[ ## Vulnerability Details **File Location**: `scripts/init-project.sh`, lines 20–37 **Vulnerability Type**: Unpinned third-party dependencies and missing reviewed lockfile baseline **Risk Level**: Medium ### Vulnerable Code ```bash cat > package.json << EOF { "name": "$PROJECT", "version": "1.0.0", "scripts": { "start": "remotion studio", "build": "remotion render src/index.tsx ${BRAND}-promo out/video.mp4", "stills": "remotion still src/index.tsx ${BRAND}-promo" }, "dependencies": { "@remotion/cli": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "remotion": "^4.0.0" }, "devDependencies": { "@types/react": "^18.2.0", "typescript": "^5.0.0" } } EOF ``` The corresponding instructions in `SKILL.md`, lines 39–45, also direct installation without a reviewed lockfile: ```bash mkdir -p remotion-{brand}-promo/{src,audio,out} cd remotion-{brand}-promo npm init -y npm install remotion @remotion/cli react react-dom npm install -D typescript @types/react ``` ### Technical Analysis The initializer uses caret version ranges, and the documentation installs packages without versions. Both approaches permit npm to resolve package releases that were not present when the skill was audited. No reviewed `package-lock.json` is included to provide an integrity and transitive-dependency baseline. As a result, two installations performed at different times may retrieve materially different code. npm packages and their transitive dependencies may execute lifecycle scripts during installation, so compromise of a permitted future release can affect the host before the project is built. No evidence was found that the named packages are currently malicious. The security issue is the unsafe, mutable dependency-resolution process and the resulting exposure to future package or registry compromise. ### Attack Path 1. A permitted package release or transitive dependency is compromised, or a vulnerable version is publis ...[truncated 1064 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin all direct dependencies to reviewed exact versions rather than caret ranges. 2. Generate, review, and distribute a `package-lock.json`. 3. Use `npm ci` for reproducible installation from the lockfile. 4. Verify lockfile integrity and review changes before dependency updates are accepted. 5. Use automated vulnerability and provenance checks, such as `npm audit`, dependency review, and registry-signature or provenance verification where available. 6. Review package lifecycle scripts and consider initially installing with: ```bash npm ci --ignore-scripts ``` Enable only lifecycle scripts that are demonstrably required and trusted. 7. Perform dependency installation and rendering in a sandbox with restricted filesystem permissions, minimal credentials, and constrained network access. 8. Adopt a controlled dependency-update process that tests and reviews new direct and transitive versions before release. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description promises a broad website-to-promotional-video capability, but the actual code only performs color extraction from a webpage and outputs a suggested palette. While color extraction could be a supporting subcomponent for branding in video generation, this chunk by itself does not implement the primary declared behavior and lacks the major advertised capabilities such as content extraction for scenes, Remotion/React composition, narration, music, or rendering. Therefore the description does not accurately represent what this supplied code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description promises an end-to-end website-to-promotional-video workflow driven by a website URL, including scraping, content extraction, Remotion animation setup, TTS narration, free BGM, and rendering. The supplied code only initializes a project skeleton: it creates directories and config files, sets up package.json and a Remotion composition stub, writes placeholder narration text, and downloads a background music file. Although downloading free BGM and basic Remotion setup align partially with the description, the core advertised behavior—turning a website into a video—is absent. The provided URL parameter is not used for scraping or content generation at all. Therefore the description materially overstates the implemented functionality.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill clearly instructs use of shell and network operations (`python3`, `curl`, `npm`, `npx remotion`) but declares no `permissions` or `allowed-tools` scope. That creates an overbroad execution surface where an agent may invoke powerful capabilities without an explicit least-privilege contract, increasing the risk of unintended external access, downloads, and command execution.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The description states the output includes Chinese narration, imposing a specific language by default. The file does not present this as an opt-in choice or explain that the skill is limited to a Chinese-language context.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The skill directs scraping and remote fetching of user-supplied websites without clearly warning that the URL and retrieved content will be transmitted to external services or remote hosts. This can expose sensitive internal URLs, private staging sites, or confidential content to third parties and can also trigger unwanted outbound requests from the agent environment.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The workflow instructs downloading packages and media from the internet (`npm install`, `curl` to Pixabay) without explicit warning or consent. This exposes the runtime to supply-chain, licensing, and privacy risks, especially if executed automatically in a privileged environment.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The instructions require use of the TTS tool to generate Chinese narration, which is a natural-language locale constraint. No alternative language path or user preference check is provided.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
Using `npx remotion` without a pinned version allows whatever package version is current at execution time to be fetched and run. This creates a supply-chain risk: behavior can change unexpectedly, and a compromised or malicious upstream package version could execute arbitrary code in the agent environment.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
This `npx remotion` invocation is also unpinned, so it may download and execute an arbitrary current version from the registry. In an automated skill context, repeated dynamic package execution materially increases supply-chain exposure.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The command at this line relies on `npx remotion` without version pinning, exposing the environment to uncontrolled upstream changes and potential arbitrary code execution from dependencies. Because the skill encourages users to run these commands directly, the risk is practical rather than theoretical.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
This screenshot-generation command again uses an unpinned `npx remotion`, which can fetch code at runtime. Any compromise or incompatible upstream change could affect the host, outputs, or subsequent automated steps.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The skill repeats the same unpinned package execution pattern here, compounding supply-chain risk across multiple workflow steps. In agentic environments, such patterns are dangerous because the commands may run non-interactively with filesystem and network access.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
This final `npx remotion` occurrence shares the same vulnerability: dynamic execution of an unpinned remote package. Multiple occurrences indicate a systemic reproducibility and supply-chain security issue in the skill design.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The constraints section says 'Chinese Narration' is required for all segments, making the language requirement mandatory rather than optional. This forces a specific locale without user choice.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
`extract_colors` returns `filtered`, which is a plain dictionary built at L31-L39, but `main()` treats `colors` as if it were still a `Counter` by calling `colors.most_common(10)`. This conflicts with the apparent intent of printing the top colors and indicates the code/documented behavior is out of sync with the implementation.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The script automatically fetches an external MP3 via curl, which is a network operation that contacts a third-party host. Although it prints "Downloading free BGM...", that message does not clearly disclose the remote source or that data is being transmitted to an external service.

Static analysis

No suspicious patterns detected.