Back to skill

Security audit

OpenClaw NovelAI

Security checks across malware telemetry and agentic risk

Overview

This skill is a disclosed NovelAI workflow helper, with the main cautions being the required NovelAI token, a pinned third-party image MCP dependency, and local generation records.

Install only if you are comfortable configuring NOVELAI_TOKEN in the host environment and trusting the pinned novelai-image-mcp package after review. Do not paste tokens into chat, prompts, metadata files, or config examples, and consider running the MCP server with limited filesystem and network 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 (2)

T08 · Insecure Dependencies

Warning
Location
examples/openclaw.config.example.json5:23
Finding
Third-Party MCP Package Is Retrieved and Executed with Access to the NovelAI Credential<![CDATA[ ## Vulnerability Details **File Location**: `examples/openclaw.config.example.json5:23-29`; equivalent configuration is documented in `docs/FULL-USER-MANUAL.md:116-125` **Vulnerability Type**: Supply-chain exposure through runtime package retrieval and execution **Risk Level**: Medium ### Complete Code Snippet ```json5 "novelai-image": { command: "uvx", // Pin the audited upstream release; do not silently follow latest. args: ["--from", "novelai-image-mcp==0.4.0", "novelai-image-mcp", "serve"], env: { NOVELAI_TOKEN: "${NOVELAI_TOKEN}", }, }, ``` ### Technical Analysis The configuration instructs `uvx` to retrieve and execute the separately maintained `novelai-image-mcp` package. Pinning the package to version `0.4.0` reduces exposure to silent version upgrades, but it does not establish artifact integrity because no package hash, immutable artifact digest, or fully locked transitive dependency graph is enforced. The launched package receives `NOVELAI_TOKEN` directly in its environment. It also necessarily has network access for NovelAI operations and may inherit the filesystem permissions of the OpenClaw Gateway account. Consequently, compromise of the package publisher, package registry, referenced release, or an unresolved transitive dependency could turn the MCP process into a credential or data-exfiltration mechanism. The repository explicitly identifies this MCP server as an independent third-party dependency and advises operators to review it. There is no evidence that the package is currently malicious; the vulnerability is the trust and execution model. ### Attack Path 1. An attacker compromises the package publisher account, package registry, pinned release artifact, or a transitive dependency resolved by `uvx`. 2. The operator starts OpenClaw using the supplied MCP configuration. 3. `uvx` retrieves and executes the compromised package. 4. OpenClaw passes `NOVELAI_TOKEN` into the MCP process environment. 5. Malicious pac ...[truncated 803 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Install the MCP server from an operator-reviewed, immutable artifact instead of resolving it dynamically whenever the service starts. 2. Lock and verify the complete dependency graph with cryptographic hashes, including transitive dependencies. 3. Verify package provenance, signatures, publisher identity, and release artifacts before deployment. 4. Run the MCP server under a dedicated low-privilege operating-system account or isolated container. 5. Restrict filesystem access to only required input and output directories. 6. Restrict outbound network access to the documented NovelAI endpoints. 7. Supply a narrowly scoped or revocable credential where the provider supports one, and rotate it after any suspected dependency compromise. 8. Preserve the existing version pin and require explicit review, smoke testing, and integrity verification before upgrades. 9. Avoid granting broad tool permissions merely to support the MCP server; use the narrowest host allowlist available. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/project_state.py:29
Finding
Generation Record Redaction Can Persist Secrets Stored Under Neutral Keys or Inside Prompts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/project_state.py:29-36`, `scripts/project_state.py:59-67`, and `scripts/project_state.py:171-201` **Vulnerability Type**: Incomplete sensitive-data redaction before persistent storage **Risk Level**: Low ### Complete Code Snippets The sensitive-key list and redaction implementation are: ```python SENSITIVE_KEY_PARTS = ( "token", "secret", "password", "authorization", "api_key", "apikey", ) ``` ```python def is_sensitive_key(key: str) -> bool: normalized = key.lower().replace("-", "_") return any(part in normalized for part in SENSITIVE_KEY_PARTS) def redact(value: Any) -> Any: if isinstance(value, dict): return { key: "[REDACTED]" if is_sensitive_key(str(key)) else redact(item) for key, item in value.items() } if isinstance(value, list): return [redact(item) for item in value] return value ``` The record is constructed from user-controlled prompts and metadata, redacted, and written to disk: ```python def command_record(args: argparse.Namespace) -> dict[str, Any]: project = project_path(args.project_dir) metadata: dict[str, Any] = {} if args.metadata_file: metadata_path = Path(args.metadata_file).expanduser().resolve() if not metadata_path.is_file(): raise ValueError(f"Metadata file does not exist: {metadata_path}") loaded = json.loads(read_text_file(metadata_path)) if not isinstance(loaded, dict): raise ValueError("Metadata file must contain a JSON object") metadata.update(loaded) asset_path = Path(args.asset).expanduser().resolve() if args.asset else None asset: dict[str, Any] | None = None if asset_path: try: relative = asset_path.relative_to(project) asset = {"path": relative.as_posix(), "scope": "project"} except ValueError: asset = {"path": asset_path.name, ...[truncated 2634 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Recursively inspect both keys and string values before writing records. 2. Reject or redact recognizable authorization-header forms and known credential prefixes in every string field. 3. Explicitly validate `prompt`, `negative_prompt`, and all imported metadata values before persistence. 4. Where safe, compare candidate values against sensitive environment variables without logging or returning those variables. 5. Prefer rejecting a suspicious record over silently persisting partially sanitized data. 6. Allow operators to configure additional sensitive key names and credential patterns. 7. Write metadata files with restrictive permissions appropriate to the operating system. 8. Add unit tests covering: - secrets under neutral keys; - secrets embedded in prompts; - nested lists and dictionaries; - mixed-case authorization headers; - additional API-token formats; - confirmation that errors and returned objects do not echo detected secrets. 9. Continue enforcing the documented policy that credentials must never be placed in prompts, command arguments, metadata files, or chat. ]]>
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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep

VirusTotal

65/65 vendors flagged this skill as clean.

View on VirusTotal

Static analysis

Detected: suspicious.exposed_secret_literal, suspicious.secret_argv_exposure

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
docs/FULL-USER-MANUAL.md:503

Instructions pass high-value credentials through process argv.

Critical
Code
suspicious.secret_argv_exposure
Location
SKILL.md:139