Back to skill

Security audit

Claude Code Agent

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned for MCP orchestration, but it gives configured tool servers broad local execution and credential exposure without enough user control or warning.

Install only if you are comfortable treating each configured MCP server as trusted local code. Use pinned, reviewed server packages; avoid npx -y for runtime startup; do not store real tokens directly in shared config files; run with a minimal environment; and avoid syncing or persisting secrets, regulated data, or sensitive chat/tool output until the package provides clearer controls and documentation.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
src/store/sync.ts:8
Finding

Prototype Pollution in Recursive State Merge

Content
View full analysis
(target: T, source: Partial): T { for (const key of Object.keys(source) as (keyof T)[]) { const sourceValue = source[key]; const targetValue = target[key]; if ( sourceValue !== undefined && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) ) { if (typeof targetValue !== "object" || targetValue === null) { (target as any)[key] = {}; } merge(target[key] as object, sourceValue as object); } else if (sourceValue !== undefined) { (target as any)[key] = sourceValue; } } return target; } ``` The vulnerable function is exposed to synchronized state through: ```typescript export function mergeWithUpdate( localState: T, remoteState: T, ): T { const localUpdateTime = localState.lastUpdateTime ?? 0; const remoteUpdateTime = remoteState.lastUpdateTime ?? 1; if (localUpdateTime < remoteUpdateTime) { merge(remoteState, localState); return { ...remoteState }; } else { merge(localState, remoteState); return { ...localState }; } } ``` ### Technical Analysis The recursive `merge()` function processes every enumerable source key without rejecting special object-property names such as `__proto__`, `prototype`, or `constructor`. When attacker-controlled data parsed from JSON includes a `__proto__` property, accessing `target[key]` can resolve to the target object's inherited prototype. The recursive call can then write attacker-supplied properties into `Object.prototype`. Those properties become visible through inheritance on otherwise unrelated objects througho ...[truncated 1683 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/mcp/client.ts:18
Finding

Unrestricted MCP Subprocesses Inherit the Complete Parent Environment

Content
View full analysis
v !== undefined) .map(([k, v]) => [k, v as string]), ), ...(config.env || {}), }, }); ``` The public server-management API accepts and initializes arbitrary command configurations: ```typescript export async function addMcpServer(clientId: string, config: ServerConfig) { try { const currentConfig = await getMcpConfigFromFile(); const isNewServer = !(clientId in currentConfig.mcpServers); if (isNewServer && !config.status) { config.status = "active"; } const newConfig = { ...currentConfig, mcpServers: { ...currentConfig.mcpServers, [clientId]: config, }, }; await updateMcpConfig(newConfig); if (isNewServer || config.status === "active") { await initializeSingleClient(clientId, config); } return newConfig; } catch (error) { logger.error(`Failed to add server [${clientId}]: ${error}`); throw error; } } ``` Configuration files are also parsed without schema or executable-policy validation: ```typescript export async function getMcpConfigFromFile(): Promise { try { const configStr = await fs.readFile(CONFIG_PATH, "utf-8"); return JSON.parse(configStr); } catch (error) { logger.error(`Failed to load MCP config, using default config: ${error}`); return DEFAULT_MCP_CONFIG; } } ``` ### Technical Analysis MCP servers are subprocesses and therefore necessarily execute code. Howev ...[truncated 2021 chars]
Remediation
View remediation
= { PATH: process.env.PATH ?? "", ...(config.env ?? {}), }; ``` 2. Maintain a documented allowlist of runtime variables that MCP servers may inherit. 3. Require explicit user approval before registering or starting a new executable. 4. Validate configurations with a strict runtime schema before use. 5. Restrict executable paths to reviewed, locally installed binaries where feasible. 6. Reject unexpected relative paths, shell interpreters, and commands outside an administrator-defined allowlist. 7. Run MCP servers under a dedicated low-privilege account or sandbox with: - Restricted filesystem access. - Network controls. - Resource limits. - No access to the parent application's credential stores. 8. Store server-specific credentials separately and provide only the exact credentials required by that server. 9. Clearly document that an MCP server configuration is equivalent to granting local code-execution privileges. ]]>

T08 · Insecure Dependencies

Warning
Location
mcp_config.example.json:3
Finding

Documentation Encourages Automatic Execution of Unpinned npm Packages

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (24)

MCP Config Access

High
Category
Agent Snooping
Confidence
90% 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.

Content

Scanner excerpt · README.md (reported line 148)May include surrounding context.

typescript
import { setConfigPath } from "openclaw-claude-code-skill";

setConfigPath("/path/to/your/mcp_config.json");

API Reference

MCP Config Access

High
Category
Agent Snooping
Confidence
90% 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.

Content

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

typescript
import { setConfigPath } from "openclaw-claude-code-skill";
setConfigPath("/path/to/mcp_config.json");

Requirements

MCP Config Access

High
Category
Agent Snooping
Confidence
90% 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.

Content

Scanner excerpt · examples/basic-mcp.ts (reported line 19)May include surrounding context.

ts
async function main() {
  // Optional: Set a custom config path
  setConfigPath("./mcp_config.json");

  // Initialize the MCP system
  console.log("Initializing MCP system...");

MCP Config Access

High
Category
Agent Snooping
Confidence
90% 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.

Content

Scanner excerpt · src/mcp/actions.ts (reported line 352)May include surrounding context.

ts
const configStr = await fs.readFile(CONFIG_PATH, "utf-8");
    return JSON.parse(configStr);
  } catch (error) {
    logger.error(`Failed to load MCP config, using default config: ${error}`);
    return DEFAULT_MCP_CONFIG;
  }
}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README promotes state persistence and session synchronization for app or conversation data but does not warn that sensitive content may be stored locally in IndexedDB/localStorage and merged across devices. In an AI assistant context, this can expose prompts, chat history, tokens, or other sensitive state to unintended access on shared devices or through insecure sync assumptions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README shows a GitHub token embedded directly in MCP server configuration without any guidance on secure credential handling. Users may copy this pattern into files that are committed, shared, or left readable on disk, causing credential leakage and unauthorized repository access.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

Advertising session persistence without warning about sensitive data retention is a real security concern, especially for an MCP integration that may handle tool requests, filesystem paths, responses, and credentials. Retained session data increases exposure to local compromise, unintended sharing, and recovery of past sensitive context.

Content

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

md
MCP (Model Context Protocol) integration for OpenClaw/Clawdbot. Use when you need to:
- Connect and orchestrate MCP tool servers (filesystem, GitHub, etc.)
- Persist state across sessions with IndexedDB/localStorage
- Sync sessions across multiple devices

Triggers: "MCP", "tool server", "sub-agent orchestration", "session sync", "state persistence", "Claude Code integration"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill advertises persistence across sessions and cross-device session synchronization without warning about what user data may be stored, how long it is retained, or where it is synced. In a tool-orchestration context, persisted state can easily include prompts, tool outputs, file paths, tokens, or other sensitive operational data, so omission of privacy and data-handling guidance creates real risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The configuration example includes a GitHub token directly in JSON without any warning about secret handling. This encourages insecure practices such as storing credentials in plaintext config files, committing them to source control, or exposing them through logs and shared session state.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Removing an MCP server here irreversibly changes saved configuration and tears down the active client, but the code only logs errors and provides no user disclosure or confirmation around this destructive action. Users may not realize that invoking this function will both persistently remove the server entry and disconnect the client.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code performs persistent filesystem writes to the MCP configuration file, including creating directories and overwriting the config contents. While the operation is implied by the function name, there is no user-facing disclosure, confirmation, or warning in this code path about modifying on-disk configuration.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Creating a StdioClientTransport launches an external command from configuration, which is a trust-boundary crossing with subprocess execution risk. While spawning a process is core to MCP stdio operation and not inherently malicious, doing so without explicit warning or trust validation can cause users to run unintended local programs with the application's privileges.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The client spawns an external MCP server process and forwards nearly the entire parent process environment into it, only filtering out undefined values. This can expose API keys, tokens, cloud credentials, and internal configuration to any configured server command, including untrusted or compromised local binaries, making secret exfiltration straightforward.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code passes the host process environment to the spawned subprocess without any visible warning, consent gate, or minimization. In an MCP context, where server definitions may be user-provided or less trusted, this increases the danger because the launched process can read and exfiltrate secrets immediately on startup.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

mergeWithUpdate contradicts its own contract and merges the older state into the newer object before returning it. This can silently resurrect stale fields, overwrite fresher values depending on merge direction and aliasing, and mutate caller-owned state in place, leading to state corruption during sync and potentially exposing or re-enabling outdated data.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency uses a caret range, so installs may drift to newer minor/patch releases without explicit review. In a security-sensitive agent skill that integrates MCP and orchestration components, this increases supply-chain risk and makes it harder to verify whether vulnerable or behavior-changing versions are being pulled in.

Content

Scanner excerpt · package.json (reported line 22)May include surrounding context.

json
"url": "https://github.com/enderfga/openclaw-claude-code-skill"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0",
    "zod": "^3.22.0",
    "zustand": "^4.4.0",
    "idb-keyval": "^6.2.0"

Unverifiable Dependency: @modelcontextprotocol/sdk has 3 known advisory(ies) (CVE-2026-25536 (@modelcontextprotocol/sdk has cross-client data leak via shared server/transport); CVE-2026-0621 (Anthropic's MCP TypeScript SDK has a ReDoS vulnerability); CVE-2025-66414 (Model Context Protocol (MCP) TypeScript SDK does not enable DNS rebinding protec)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The manifest does not pin @modelcontextprotocol/sdk, and the package has known advisories including cross-client data leak, ReDoS, and missing DNS rebinding protections. Because this skill explicitly enables MCP integration and sub-agent orchestration, the context makes the issue more dangerous: if an affected version is installed, it could directly impact confidentiality, availability, or network trust boundaries.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The zod dependency is specified with a caret range, which permits automatic version changes across installs. That weakens build reproducibility and can introduce unreviewed security regressions or transitively pull in affected releases.

Content

Scanner excerpt · package.json (reported line 23)May include surrounding context.

json
},
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0",
    "zod": "^3.22.0",
    "zustand": "^4.4.0",
    "idb-keyval": "^6.2.0"
  },

Unverifiable Dependency: zod has 1 known advisory(ies) (CVE-2023-4316 (Zod denial of service vulnerability)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The zod dependency is not pinned, and there is a known denial-of-service advisory affecting some versions. Without an exact resolved version, it is impossible to confirm from the manifest alone whether deployments are safe, and input-validation libraries are often exercised on attacker-controlled data.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

Using a ranged version for zustand allows different environments to resolve different package contents over time. For an agent skill, this can complicate trust and auditing of the runtime dependency set and create avoidable supply-chain exposure.

Content

Scanner excerpt · package.json (reported line 24)May include surrounding context.

json
"dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0",
    "zod": "^3.22.0",
    "zustand": "^4.4.0",
    "idb-keyval": "^6.2.0"
  },
  "devDependencies": {

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The idb-keyval package is not pinned to an exact version, so future installs may silently consume newer releases. This is a classic supply-chain hygiene issue that reduces reproducibility and can expose consumers to newly introduced vulnerable code.

Content

Scanner excerpt · package.json (reported line 25)May include surrounding context.

json
"@modelcontextprotocol/sdk": "^1.0.0",
    "zod": "^3.22.0",
    "zustand": "^4.4.0",
    "idb-keyval": "^6.2.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
84% confidence
Finding

The TypeScript compiler is a development dependency, but leaving it unpinned still weakens build determinism. While less directly exploitable at runtime, toolchain drift can affect generated artifacts and introduce security-relevant differences between builds.

Content

Scanner excerpt · package.json (reported line 28)May include surrounding context.

json
"idb-keyval": "^6.2.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "@types/node": "^20.0.0"
  },
  "scripts": {

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
82% confidence
Finding

The @types/node package is unpinned, which can change build-time behavior and type expectations over time. This is lower risk than a runtime dependency, but it still harms reproducibility and may mask or introduce security-relevant implementation changes.

Content

Scanner excerpt · package.json (reported line 29)May include surrounding context.

json
},
  "devDependencies": {
    "typescript": "^5.0.0",
    "@types/node": "^20.0.0"
  },
  "scripts": {
    "build": "tsc",

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This function changes the server's saved status to paused and removes the active client connection, affecting system behavior beyond the current session. The code does not present any user-facing notice or confirmation that pausing will update the config file and terminate the client.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.