Back to skill

Security audit

Visla AI Video Creation

Security checks for vulnerabilities and agentic risk

Overview

This Visla video skill is mostly purpose-aligned, but it has review-worthy risks around automatic credential-file reading and unrestricted local URL validation.

Install only if you are comfortable with this skill using Visla credentials, uploading selected content to Visla/S3, and consuming Visla credits. Before use, prefer environment variables over the saved credentials file, avoid submitting confidential files or internal URLs, and treat the URL command as risky on networks with private services until URL validation is restricted.

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/visla_cli.py:764
Finding

Blind Server-Side Request Forgery Through Unrestricted URL Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/visla_cli.py:764-785
Vulnerability Type: Blind server-side request forgery (SSRF)
Risk Level: High

Vulnerable Code

python
def validate_url(self, url):
    """Check if URL is accessible (follows redirects; falls back to GET on HEAD block).

    Sends a browser-like User-Agent: many sites (e.g. Wikipedia) block the
    default Python-urllib / python-requests UA strings with 403.
    """
    ua = (
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
        "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36"
    )
    response = self._http_request(
        "HEAD", url, headers={"User-Agent": ua},
        timeout=10, allow_redirects=True,
    )
    if response.error is None and response.status < 400:
        return True
    # Some sites block HEAD requests, retry with a lightweight ranged GET.
    if response.status in (403, 405):
        response = self._http_request(
            "GET", url, headers={"Range": "bytes=0-0", "User-Agent": ua},
            timeout=10, allow_redirects=True,
        )
        return response.error is None and response.status < 400
    return False

Technical Analysis

The URL supplied to the url command is passed directly to the local HTTP client. The validation routine does not:

  • Restrict the URL scheme to HTTP or HTTPS.
  • Reject loopback, private, link-local, multicast, reserved, or unspecified IP addresses.
  • Block cloud metadata endpoints such as link-local metadata services.
  • Resolve and validate the destination address before connecting.
  • Revalidate each destination reached through an HTTP redirect.
  • Protect against DNS rebinding or hostnames that resolve to internal addresses.

The method first sends a HEAD request. If the server responds with HTTP 403 or 405, it sends a ranged GET request. Redirect following is enabled in both cases. Cons ...[truncated 2191 chars]

Remediation
View remediation

Remediation Suggestions

  1. Permit only explicit http and https schemes and reject URLs containing embedded credentials.
  2. Resolve the hostname before connecting and reject every address classified as loopback, private, link-local, multicast, reserved, or unspecified.
  3. Explicitly block known metadata destinations and relevant IPv4 and IPv6 ranges.
  4. Disable automatic redirect following. If redirects are required, process them manually and repeat full scheme, hostname, DNS, and IP validation for every redirect target.
  5. Protect against DNS rebinding by ensuring the validated address is the address used for the connection, or enforce destination controls through a trusted outbound proxy.
  6. Consider removing local reachability validation entirely. The URL can instead be submitted to the intended Visla API after basic syntactic validation.
  7. Add tests for loopback addresses, IPv6 loopback, private ranges, decimal or encoded IP representations, link-local addresses, metadata endpoints, and public-to-private redirect chains.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/visla_cli.py:1524
Finding

Saved Credentials Are Read Without the User Consent Required by the Skill Policy

Content
View full analysis

Vulnerability Details

File Location: scripts/visla_cli.py:1524-1528
Vulnerability Type: Unenforced consent boundary for sensitive credential access
Risk Level: Medium

Vulnerable Code

python
# Auto-detect credentials from default path only
if (not api_key or not api_secret) and os.path.exists(DEFAULT_CREDENTIALS_PATH):
    file_key, file_secret = load_credentials_from_file(DEFAULT_CREDENTIALS_PATH)
    api_key = api_key or file_key
    api_secret = api_secret or file_secret

The conflicting documented requirement appears in SKILL.md:28-33:

markdown
1. Check if `~/.config/visla/.credentials` exists (do NOT read it yet).
2. If the file exists, use a **choice-based confirmation** to ask the user:
   "Found saved credentials. Allow reading `~/.config/visla/.credentials`?"
   Options: **Allow** / **No**
3. If the user selects **Allow**: proceed with the command.

Technical Analysis

The Skill documentation establishes an explicit authorization boundary: the agent may check whether the credentials file exists, but it must not read the file until the user selects Allow. The implementation does not receive or verify any consent signal. Whenever either credential is unavailable through command-line arguments or environment variables, the CLI checks for the default file and reads it automatically.

Documentation alone does not enforce a security boundary. Any caller can invoke the script directly, or an agent can inadvertently skip the documented confirmation, causing the API key and secret to be loaded without informed user approval.

The reviewed implementation uses the loaded credentials to authenticate requests to the declared Visla API and does not contain an unrelated credential-exfiltration path. The issue is therefore unauthorized access to sensitive local data relative to the Skill's stated consent model, rather than evidence that the credentials are intentionally stolen. ...[truncated 1387 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove implicit credentials-file loading from the default execution path.
  2. Introduce an explicit option such as --allow-credentials-file, defaulting to false. Read the file only when that option is present.
  3. Have the agent request the documented choice-based confirmation and pass the explicit authorization flag only after the user selects Allow.
  4. If direct interactive CLI use must be supported, prompt through a terminal only when standard input is interactive. Fail closed in non-interactive execution unless explicit authorization was supplied.
  5. Do not treat file existence as permission to access file contents.
  6. Prefer environment injection, operating-system credential storage, or protected standard input over --secret, because command-line secrets may appear in shell history or process listings.
  7. Add automated tests confirming that the credentials file is not opened without explicit authorization and that selecting No causes the command to fail without reading it.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (14)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**Script**: `scripts/visla_cli.py` — pure Python standard library (**no third-party dependencies**, no

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**Script**: `scripts/visla_cli.py` — pure Python standard library (**no third-party dependencies**, no

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**Script**: `scripts/visla_cli.py` — pure Python standard library (**no third-party dependencies**, no

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**Script**: `scripts/visla_cli.py` — pure Python standard library (**no third-party dependencies**, no

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**Script**: `scripts/visla_cli.py` — pure Python standard library (**no third-party dependencies**, no

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**Script**: `scripts/visla_cli.py` — pure Python standard library (**no third-party dependencies**, no

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
**Script**: `scripts/visla_cli.py` — pure Python standard library (**no third-party dependencies**, no

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares capabilities that imply environment access, local file access, and network use, but it does not explicitly scope or constrain those powers with a permissions or allowed-tools declaration. That creates an avoidable trust gap: the runtime may still permit sensitive actions, while reviewers and policy systems have no machine-readable boundary for what the skill is supposed to do.

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 · SKILL.md (reported line 18)May include surrounding context.

md
**Version: 260811-1640**

Create AI-generated videos from text scripts, web URLs, documents (PPT/PDF), or AI-generated visuals (AIGC) using Visla's
OpenAPI. AIGC generates original storyboard images and motion videos for each scene with AI instead of matching stock
footage.

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 · SKILL.md (reported line 269)May include surrounding context.

md
The `script`, `url`, `doc`, `idea`, `visual`, and `speech` commands execute the complete flow automatically:

1. Create project
2. Poll until generation completes (may take a few minutes)
3. Auto-export and return download link

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Scripts and idea text entered by the user are sent to the remote Visla API without an explicit warning that the content leaves the local environment. In a skill setting, this can expose proprietary plans, internal scripts, or sensitive prompts if the user believes the tool is only formatting or generating content locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This CLI uploads user-supplied local documents and media files to Visla/S3 as part of its normal workflow, but it does not provide an explicit privacy or data-transmission warning at the point of use. In an agent/skill context, users may assume local files are processed locally; silently transmitting potentially sensitive PDFs, PPTs, audio, images, or videos to third-party services can cause unintended disclosure of confidential data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The instructions explicitly require organizing voice options by language/region categories such as US English, Chinese, Japanese, and French. This imposes a locale-based presentation policy without stating that the user can choose a preferred language or locale, which falls under the language/locale policy concerns for natural-language instructions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The voice-listing request always passes localeName='en-US', which constrains results to a specific locale regardless of user preference. This is a natural-language/locale policy issue because the file does not offer an opt-in locale choice or explain why English (US) is required.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.