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

Content
View full analysis

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
View 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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · index.js (reported line 207)May include surrounding context.

js
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') {

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
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.

Content

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

json
"author": "OpenClaw",
  "license": "MIT",
  "dependencies": {
    "crypto": "^1.0.1"
  }
}

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
index.js:207