Back to skill

Security audit

evomap-bundle-improve

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its bundle-validation purpose, but its publish path can execute injected shell commands from bundle content and it rewrites important bundle metadata in place.

Review before installing or running this skill on any bundle you do not fully trust. Avoid publish and publish-all until the shell-based curl call is replaced with a safe HTTP client, and keep backups because enhance, fix, and publish rewrite bundles, identifiers, and provenance-like fields in place.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
index.js:214
Finding
Arbitrary Shell Command Injection Through Bundle Content## Vulnerability Details **File Location**: `index.js`, lines 214–220 **Vulnerability Type**: OS command injection through unsafe shell-command construction **Risk Level**: High ### Vulnerable Code ```javascript const { execSync } = require('child_process'); const data = fs.readFileSync(filePath, 'utf8'); try { const result = execSync('curl -s -X POST ' + EVOMAP_API + ' -H "Content-Type: application/json" -d \'' + data + '\'', { encoding: 'utf8' }); const response = JSON.parse(result); ``` ### Technical Analysis `publishBundle()` reads the contents of a user-selected bundle file and directly concatenates them into a command passed to `child_process.execSync()`. Because `execSync()` executes the constructed string through a shell, shell metacharacters in `data` are interpreted as command syntax. The request body is enclosed in single quotes, but bundle content is not escaped. A single quote in any attacker-controlled JSON string can terminate the quoted `curl` argument. The attacker can then append shell commands and use further syntax, such as a comment marker, to neutralize the remainder of the generated command. Apostrophes are valid JSON string content, so the expected input format does not prevent this condition. Parsing and rewriting by `fixBundle()` do not provide shell escaping. Attacker-controlled fields such as summaries, signals, strategies, and other retained properties can therefore carry the injection payload into the subsequent publishing operation. ### Attack Path 1. An attacker creates or modifies an EvoMap bundle containing shell syntax in a JSON string field. 2. The victim obtains that bundle and invokes either: - `node index.js publish <bundle.json>`, or - `node index.js publish-all <directory>`. 3. `fixBundle()` parses and rewrites the bundle but preserves attacker-controlled data fields. 4. `publishBundle()` reads the resulting file as raw text. 5. The raw text is ...[truncated 1135 chars]
Remediation
## Remediation Suggestions 1. Eliminate shell execution from the publication path. Use Node.js `fetch()` or `https.request()` and pass the bundle as the HTTP request body: ```javascript async function publishBundle(filePath) { const data = fs.readFileSync(filePath, 'utf8'); const parsed = JSON.parse(data); const response = await fetch(EVOMAP_API, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(parsed) }); if (!response.ok) { throw new Error(`Publish failed with HTTP ${response.status}`); } return await response.json(); } ``` 2. If invoking `curl` is unavoidable, use `execFileSync()` or `spawn()` with a separate argument array and shell processing explicitly disabled. Do not construct a command string: ```javascript const { execFileSync } = require('child_process'); const result = execFileSync( 'curl', [ '-s', '-X', 'POST', EVOMAP_API, '-H', 'Content-Type: application/json', '--data-binary', data ], { encoding: 'utf8', shell: false } ); ``` 3. Parse the file as JSON and validate its schema before publication. This is defense in depth and must not replace removal of shell interpolation. 4. Add regression tests containing apostrophes and shell metacharacters in every user-controlled string field. Verify that these values are transmitted literally and never executed. 5. Propagate publication failures safely and avoid printing sensitive server responses or command details to logs.
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documented behavior goes beyond simple validation/optimization into local file writes, identifier rewriting, batch processing, and external publishing without corresponding permission declarations or prominent disclosure. This mismatch can mislead users or orchestrators into invoking a skill with broader side effects than expected, including data exfiltration or integrity-impacting changes.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises shell-based commands and file-processing behavior but does not declare any explicit tool scope or permissions. This is dangerous because consumers and enforcement layers cannot reliably distinguish read-only validation from potentially destructive local execution, batch modification, or publish workflows.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The auto-fix and auto-enhance descriptions normalize automatic mutation of bundle files and metadata without clearly warning users that local artifacts will be modified. In a packaging or identity-based ecosystem, silent rewrites can break provenance, invalidate expectations, and propagate unintended changes across many files.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill describes a publish command but gives no warning that bundle contents may be transmitted to an external service. Users may assume a local validation workflow and unintentionally disclose proprietary bundle content, metadata, or identifiers.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Recomputing asset_id hashes and rewriting cross-references changes object identity and linkage, yet the documentation does not warn about the consequences. This can irreversibly alter references, break downstream trust or lookup mechanisms, and cause users to publish mutated assets under new identities without realizing it.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The skill goes beyond validation and repair by automatically inflating confidence and success metrics, expanding triggers, and generating marketing-style summaries/content. This is dangerous because it can fabricate trust signals and alter semantic meaning of bundles, misleading downstream systems or reviewers about provenance, quality, and observed effectiveness.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The code creates missing EvolutionEvent records and derives asset/provenance-like identifiers even when the original bundle lacked them. Synthesizing event history and linkage metadata can misrepresent the bundle as having observed execution history or provenance that did not actually exist, which can poison trust and audit workflows.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The tool overwrites the input bundle in place after making substantial semantic changes, including generated content and metadata changes, without backup, confirmation, or dry-run default. In a security-sensitive publishing workflow, silent in-place mutation can destroy evidence, erase provenance, or cause users to submit altered artifacts they did not intend to modify.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The skill invokes a shell command to publish bundle contents to a remote service, which exceeds a pure validator role and introduces command-execution and data-exfiltration risk. Because the command is built by string concatenation around unescaped JSON data, crafted bundle content containing a single quote can break shell quoting and potentially trigger shell injection.

External Transmission

Medium
Category
Data Exfiltration
Content
const data = fs.readFileSync(filePath, 'utf8');
  
  try {
    const result = execSync('curl -s -X POST ' + EVOMAP_API + ' -H "Content-Type: application/json" -d \'' + data + '\'', { encoding: 'utf8' });
    const response = JSON.parse(result);
    
    if (response.payload?.decision === 'accept') {
Confidence
98% confidence
Finding
This is a real external-transmission behavior: the file contents are read and POSTed to a third-party endpoint. In this skill's context, that is more dangerous because the advertised role centers on validation/fixing, not data export, so the transmission may violate user expectations and expose sensitive bundle contents or metadata.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill sends full bundle contents to a remote API without a clear up-front warning about network transmission, which can expose sensitive bundle data, internal logic, or embedded secrets. In context, the tool is framed as a validator/fixer, so automatic publication increases the chance users will not realize local files are being transmitted externally.

Intent-Code Divergence

Low
Confidence
96% confidence
Finding
The warning text states the Gene is 'missing content', but the condition also triggers when content exists and is simply too short. This is a direct mismatch between the inline diagnostic message and the implemented behavior.

Intent-Code Divergence

Low
Confidence
96% confidence
Finding
The Capsule warning message claims content is missing, but the condition fires for either absent content or content under the 50-character threshold. The message therefore contradicts what the code is evaluating.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"author": "OpenClaw",
  "license": "MIT",
  "dependencies": {
    "crypto": "^1.0.1"
  }
}
Confidence
90% confidence
Finding
The dependency is specified with a caret range, which allows newer minor and patch versions to be installed without review. That creates supply-chain risk because a compromised or breaking upstream release could be pulled in unexpectedly; in this case the risk is somewhat limited because the package is small and the dependency appears unnecessary for modern Node.js, where crypto is built in.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
index.js:207