Back to skill

Security audit

Clawvisual

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for carousel generation, but it needs Review because it can store and transmit API keys and user content, auto-start a detached local service, and invoke broad MCP tools without enough safeguards.

Install only if you are comfortable with a global npm CLI that can start a local web/MCP service and store API keys on disk. Keep `CLAWVISUAL_MCP_URL` on localhost or HTTPS, avoid submitting sensitive or proprietary content unless the configured LLM/MCP service is approved, secure or remove `~/.clawvisual/config.json`, and treat the raw MCP call command as developer-level access.

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/clawvisual-mcp-client.mjs:248
Finding
Sensitive RPC Data Can Be Transmitted over Cleartext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clawvisual-mcp-client.mjs:26-27, 248-265, 440-450, 489-500, 523-528` **Vulnerability Type**: Cleartext transmission of credentials and potentially sensitive user content **Risk Level**: High ### Vulnerable Code ```js const BASE_URL = process.env.CLAWVISUAL_MCP_URL || getConfigValue(LOCAL_CONFIG, "CLAWVISUAL_MCP_URL") || "http://localhost:3000/api/mcp"; const API_KEY = process.env.CLAWVISUAL_API_KEY || getConfigValue(LOCAL_CONFIG, "CLAWVISUAL_API_KEY"); ``` ```js async function rpc(method, params = {}, id = 1) { const headers = { "Content-Type": "application/json" }; if (API_KEY) { headers["x-api-key"] = API_KEY; } const res = await fetch(BASE_URL, { method: "POST", headers, body: JSON.stringify({ jsonrpc: "2.0", id, method, params }) }); ``` Examples of user-controlled data included in RPC requests: ```js const payload = { session_id: typeof args.session === "string" ? args.session : undefined, input_text: args.input, max_slides: slideCount, aspect_ratios: [ratio], style_preset: typeof args.style === "string" ? args.style : "auto", tone: typeof args.tone === "string" ? args.tone : "auto", generation_mode: typeof args.mode === "string" ? args.mode : "quote_slides", output_language: typeof args.lang === "string" ? args.lang : "en-US", review_mode: args.review === "required" ? "required" : "auto" }; ``` ```js const payload = { job_id: args.job, intent: args.intent === "regenerate_cover" || args.intent === "regenerate_slides" ? args.intent : "rewrite_copy_style", instruction: args.instruction, preserve_facts: true, preserve_slide_structure: true, preserve_layout: true }; ``` ```js const result = await callTool("regenerate_cover", { prompt: args.prompt, aspect_ratio: ratio }); ``` ### Technical Analysis The configured MCP endpoint accepts arbitrary URLs, including non-loopback endpoints ...[truncated 1941 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse and validate `CLAWVISUAL_MCP_URL` before sending any request. 2. Permit cleartext HTTP only for verified loopback addresses such as `localhost`, `127.0.0.1`, and, if supported, `::1`. 3. Require `https://` for every non-loopback destination. 4. Refuse to attach `x-api-key` to any cleartext remote request, even if an override is requested. 5. Consider requiring explicit user confirmation before transmitting content to a newly configured remote endpoint. 6. Optionally support an allowlist of trusted MCP hosts. 7. Avoid following redirects from HTTPS to HTTP and ensure credentials are not forwarded across origins. 8. Clearly document that conversion text, prompts, revision instructions, and job identifiers are sent to the configured service. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/clawvisual-mcp-client.mjs:41
Finding
API Keys Are Stored in Plaintext without Enforced Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/clawvisual-mcp-client.mjs:9-11, 30-44, 311-323` **Vulnerability Type**: Insecure local credential storage **Risk Level**: Medium ### Vulnerable Code ```js const CONFIG_DIR = path.join(os.homedir(), ".clawvisual"); const CONFIG_FILE = path.join(CONFIG_DIR, "config.json"); ``` ```js function readLocalConfig() { try { const raw = fs.readFileSync(CONFIG_FILE, "utf8"); const parsed = JSON.parse(raw); if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {}; return parsed; } catch { return {}; } } function writeLocalConfig(config) { fs.mkdirSync(CONFIG_DIR, { recursive: true }); fs.writeFileSync(CONFIG_FILE, `${JSON.stringify(config, null, 2)}\n`, "utf8"); } ``` ```js function handleSetCommand(argv) { const key = normalizeConfigKey(argv[0]); const value = argv[1]; if (!key || typeof value !== "string") { throw new Error("set requires: clawvisual set <key> <value>"); } const config = readLocalConfig(); config[key] = value; writeLocalConfig(config); print({ ok: true, action: "set", key, value: maskConfigValue(key, value), config_file: CONFIG_FILE }); } ``` ### Technical Analysis The `set` command stores `CLAWVISUAL_LLM_API_KEY` and `CLAWVISUAL_API_KEY` as plaintext values in `~/.clawvisual/config.json`. Although command output masks designated secrets, the underlying file remains unencrypted. More importantly, neither `mkdirSync` nor `writeFileSync` specifies restrictive permission modes. Newly created permissions therefore depend on the process umask. If the file already exists with permissive permissions, rewriting it does not repair those permissions. This can expose credentials to other local users or processes on systems with permissive umasks, shared home directories, weak container boundaries, or previously misconfigured files. ### Attack Path 1. A user runs `clawvisual set CLAWVISUAL_LLM_API_KEY <v ...[truncated 835 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create `~/.clawvisual` with mode `0700`. 2. Create and maintain `config.json` with mode `0600`. 3. Check existing directory and file permissions and repair overly broad modes before reading or writing secrets. 4. Use atomic writes through a securely created temporary file in the same protected directory, followed by a rename. 5. Prefer an operating-system credential store or secret-management service instead of a plaintext JSON file. 6. Continue masking secrets in output, but do not treat output masking as a substitute for secure storage. 7. Warn users that command-line values may be captured in shell history and provide a secure interactive input option. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:14
Finding
Installation Instructions Use an Unpinned Global npm Package<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:4, 13-16` **Vulnerability Type**: Unpinned third-party dependency and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```yaml metadata: {"clawdbot":{"emoji":"🖼️","requires":{"bins":["clawvisual"]},"install":[{"id":"npm","kind":"npm","package":"clawvisual","bins":["clawvisual"],"label":"Install clawvisual (npm)"}]}} ``` ```bash npm install -g clawvisual clawvisual set CLAWVISUAL_LLM_API_KEY "your_openrouter_key" clawvisual initialize clawvisual convert --input "https://example.com/article" --slides auto ``` ### Technical Analysis The installation metadata and quick-start instructions install the latest version of the `clawvisual` npm package without a fixed version or integrity constraint. Consequently, the code installed by users can change after this Skill has been audited. Global npm installation also increases exposure because package lifecycle scripts, if present and permitted by npm configuration, can execute during installation. The reviewed project contains only the Skill documentation and MCP client script; it does not establish that every future npm release will contain equivalent reviewed behavior. No evidence in the audited files proves that the current package is malicious. The vulnerability is the lack of reproducibility and trust pinning in the documented installation path. ### Attack Path 1. The npm package, maintainer account, publishing token, or release process is compromised, or a future release introduces unsafe behavior. 2. An attacker publishes an altered version under the same package name. 3. A user follows `npm install -g clawvisual` without specifying a reviewed version. 4. npm resolves and installs the altered latest release. 5. Malicious lifecycle code may execute during installation, or the installed CLI may execute attacker-controlled behavior when invoked. ### Impact Assessment The potential impact is equivalent to executing code with the p ...[truncated 418 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin installation to a specifically reviewed release, such as `clawvisual@<reviewed-version>`. 2. Record and verify package integrity metadata where the installation system supports it. 3. Publish checksums or signed provenance for reviewed releases. 4. Use a lockfile for repository-local installations and review dependency changes before updates. 5. Avoid elevated global installation where possible; prefer a project-local installation or an isolated execution environment. 6. Disable npm lifecycle scripts with `--ignore-scripts` when they are not required, or explicitly document and audit every required lifecycle script. 7. Link the package to a verifiable source repository and document the expected publisher identity. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (9)

MCP Config Access

High
Category
Agent Snooping
Content
- `clawvisual initialize`: probe/start local service and print Web URL.
- `clawvisual status`: check service identity (must be `clawvisual-mcp`).
- `clawvisual tools`: list MCP tools.
- `clawvisual convert --input <text_or_url> [--slides auto|1-8] [--ratio 4:5|1:1|9:16|16:9] [--lang <code>]`
- `clawvisual status --job <job_id>`: query job state and result.
- `clawvisual revise --job <job_id> --instruction <text> [--intent rewrite_copy_style|regenerate_cover|regenerate_slides]`
Confidence
80% confidence
Finding
Skill accesses MCP server configuration files (mcp.json). MCP configs contain server URLs, authentication tokens, and tool definitions — reading them allows the skill to discover and potentially abuse other tool integrations.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
The client can automatically spawn and detach a local Next.js development server when the MCP endpoint is unavailable. Even though it restricts auto-start to localhost and probes service identity, launching a background subprocess is a materially broader capability than a simple carousel-generation client and can surprise users, create persistence-like behavior during a session, and increase attack surface by exposing a local web service.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill declares no explicit tool scope or permission boundaries despite requiring environment-variable access and network-capable behavior. In an agent setting, this weakens least-privilege controls and can allow the skill to access secrets or make outbound requests without clear user-visible constraints.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation instructs users to submit URLs or long-form text to an LLM-backed local service but does not warn that this content may be transmitted to an external model provider via configured API URL/key settings. Users may unknowingly send proprietary, personal, or sensitive data to third-party services, creating confidentiality and compliance risks.

Description-Behavior Mismatch

Medium
Confidence
87% confidence
Finding
The client persists configuration, including API secrets, into a predictable file under the user's home directory (~/.clawvisual/config.json). While this appears intended for convenience rather than abuse, storing secrets locally expands the skill’s effective capability beyond the stated MCP client role and increases credential exposure risk if file permissions are weak, backups are shared, or the host is multi-user.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The code writes configuration directly to ~/.clawvisual/config.json and supports storing API keys there, but does not warn users at the point of storage that credentials will persist on disk. This is dangerous because users may assume ephemeral use, then unintentionally leave reusable secrets in plaintext or broadly readable local files.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The convert command forces output_language to en-US whenever the user does not explicitly provide --lang. This imposes a specific locale by default rather than offering a neutral choice or explicit opt-in, which can violate language/locale policy requirements.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The generic call command allows invoking arbitrary MCP tool names with arbitrary JSON arguments, bypassing the narrower command surface otherwise exposed by the CLI. In this skill context, that broadens the reachable functionality to whatever the backend MCP server offers, which may include sensitive or unsafe operations not reflected in the manifest or expected by users.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The code spawns a detached Next.js dev server automatically when initialize/tools/other commands detect the service is unavailable. Although the usage text mentions auto-start for initialize, the subprocess execution affecting the local system is not consistently disclosed at the execution point for other commands that also call ensureServerReady().

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/clawvisual-mcp-client.mjs:181

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/clawvisual-mcp-client.mjs:26

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/clawvisual-mcp-client.mjs:13