Back to skill

Security audit

Evolution State Analyzer

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but its analyzer can be pointed at any readable JSONL file and has no size limits, so users should review its scope before installing.

Install only if you trust the users or agents that can call this skill and you are comfortable with it reading evolution-memory data. Prefer constraining graphPath to an approved memory directory and adding file-size, line-length, event-count, and timeout limits before exposing it in shared or untrusted environments.

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

other

Warning
Location
index.js:11
Finding

Unrestricted Filesystem Path Allows Analysis of Arbitrary Readable JSONL Files

Content
View full analysis

Vulnerability Details

File Location: index.js, lines 11–25
Vulnerability Type: Unrestricted sensitive file access
Risk Level: Medium

Vulnerable Code

javascript
const defaultPath = path.resolve(__dirname, '../../memory/evolution/memory_graph.jsonl');
const targetPath = graphPath || defaultPath;

if (!fs.existsSync(targetPath)) {
  return { error: `Graph file not found: ${targetPath}` };
}

const events = [];
const genes = {};
const failurePatterns = {};
let lastEvent = null;
let streak = 0;
let stagnation = false;

const fileStream = fs.createReadStream(targetPath);

Technical Analysis

analyzeState accepts an unrestricted caller-provided filesystem path. The path is passed directly to fs.existsSync and fs.createReadStream without canonicalization, containment validation, an allowlist, or authorization checks.

Although input must contain valid JSONL records matching the expected event schema to produce meaningful results, the function can attempt to open any file readable by the Node.js process. Compatible files can have their gene identifiers, failure reasons, event counts, and success statistics exposed through the generated report.

The default path also accesses the Agent's persistent evolution memory. That access is consistent with the documented purpose of the skill, but it remains security-sensitive and should be explicitly constrained. This issue does not grant additional operating-system privileges; its reach is limited to the existing filesystem permissions of the hosting process.

Attack Path

  1. An attacker obtains the ability to invoke analyzeState or influence its graphPath argument.
  2. The attacker supplies an absolute path, traversal path, or symlink path to a readable JSONL file outside the intended evolution-memory directory.
  3. The function opens and parses that file without checking whether its resolved path is inside an approved directory. 4 ...[truncated 714 chars]
Remediation
View remediation

Remediation Suggestions

  • Define an explicit, trusted base directory for evolution-memory files.
  • Resolve the requested path with path.resolve and verify that it remains inside the trusted base directory using path.relative.
  • Reject absolute paths, traversal outside the approved directory, unexpected extensions, and unsupported file types.
  • Resolve and validate real paths to prevent symbolic-link escapes.
  • Require explicit authorization before allowing callers to select a non-default graph.
  • Run the process with a dedicated, least-privileged account that cannot read unrelated application files, credentials, or system data.
  • Avoid including sensitive absolute paths in externally visible error messages.
  • Log rejected path-access attempts without recording sensitive file contents.

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:18
Finding

Unbounded JSONL Processing Can Exhaust Memory and CPU

Content
View full analysis

Vulnerability Details

File Location: index.js, lines 18–76
Vulnerability Type: Uncontrolled resource consumption
Risk Level: Medium

Vulnerable Code

javascript
const events = [];
const genes = {};
const failurePatterns = {};
let lastEvent = null;
let streak = 0;
let stagnation = false;

const fileStream = fs.createReadStream(targetPath);
const rl = readline.createInterface({
  input: fileStream,
  crlfDelay: Infinity
});

for await (const line of rl) {
  if (!line.trim()) continue;
  try {
    const node = JSON.parse(line);
    
    // Adapt to MemoryGraphEvent schema
    let event = null;
    if (node.type === 'EvolutionEvent') {
      event = node;
    } else if (node.type === 'MemoryGraphEvent' && node.kind === 'outcome') {
      // Construct a virtual EvolutionEvent from outcome node
      event = {
        type: 'EvolutionEvent',
        id: node.id,
        intent: node.mutation ? node.mutation.category : 'unknown',
        genes_used: node.gene ? [node.gene.id] : [],
        outcome: node.outcome
      };
    }

    if (event) {
      events.push(event);
      
      // Track genes
      if (event.genes_used && Array.isArray(event.genes_used)) {
        for (const geneId of event.genes_used) {
          if (!genes[geneId]) genes[geneId] = { used: 0, success: 0 };
          genes[geneId].used++;
          if (event.outcome && event.outcome.status === 'success') {
            genes[geneId].success++;
          }
        }
      }

      // Track failures
      if (event.outcome && event.outcome.status !== 'success') {
        const reason = event.outcome.reason || 'unknown';
        failurePatterns[reason] = (failurePatterns[reason] || 0) + 1;
      }

Technical Analysis

The parser streams the input file, but it retains every accepted event in the events array. It also creates persistent aggregation entries for ...[truncated 1940 chars]

Remediation
View remediation

Remediation Suggestions

  • Check the file size with fs.stat before opening it and reject files above a documented limit.
  • Enforce a maximum number of processed events and a maximum permitted line length.
  • Stop retaining all events. Maintain only aggregate counters and a fixed-size queue containing the five most recent events.
  • Cap the number and length of unique gene IDs and failure reasons.
  • Validate each parsed record against a strict schema, including limits for arrays, strings, and nested objects.
  • Abort processing after a configured deadline or when an AbortSignal is triggered.
  • Handle stream and parsing failures explicitly and close the stream when any limit is exceeded.
  • Apply request-level rate limits and memory isolation when this function is exposed through a service.
  • Add tests covering oversized files, very long lines, excessive unique keys, deeply nested records, and early-abort behavior.
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

Static analysis

No suspicious patterns detected.