diff --git a/.claude/helpers/intelligence.cjs b/.claude/helpers/intelligence.cjs index e4cc631..a182ace 100644 --- a/.claude/helpers/intelligence.cjs +++ b/.claude/helpers/intelligence.cjs @@ -259,7 +259,19 @@ function parseMemoryDir(dir, entries) { try { const files = fs.readdirSync(dir).filter(f => f.endsWith('.md')); for (const file of files) { + // Validate file name to prevent path traversal + if (file.includes('..') || file.includes('/') || file.includes('\\')) { + continue; + } + const filePath = path.join(dir, file); + // Additional validation: ensure resolved path is within the base directory + const resolvedPath = path.resolve(filePath); + const resolvedDir = path.resolve(dir); + if (!resolvedPath.startsWith(resolvedDir)) { + continue; // Path traversal attempt detected + } + const content = fs.readFileSync(filePath, 'utf-8'); if (!content.trim()) continue; diff --git a/.claude/helpers/metrics-db.mjs b/.claude/helpers/metrics-db.mjs index 510ada9..cbe6344 100755 --- a/.claude/helpers/metrics-db.mjs +++ b/.claude/helpers/metrics-db.mjs @@ -7,7 +7,7 @@ import initSqlJs from 'sql.js'; import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'fs'; -import { dirname, join, basename } from 'path'; +import { dirname, join, basename, resolve } from 'path'; import { fileURLToPath } from 'url'; import { execSync } from 'child_process'; @@ -154,7 +154,19 @@ function countFilesAndLines(dir, ext = '.ts') { try { const entries = readdirSync(currentDir, { withFileTypes: true }); for (const entry of entries) { + // Validate entry name to prevent path traversal + if (entry.name.includes('..') || entry.name.includes('/') || entry.name.includes('\\')) { + continue; + } + const fullPath = join(currentDir, entry.name); + // Additional validation: ensure resolved path is within the base directory + const resolvedPath = resolve(fullPath); + const resolvedCurrentDir = resolve(currentDir); + if (!resolvedPath.startsWith(resolvedCurrentDir)) { + continue; // Path traversal attempt detected + } + if (entry.isDirectory() && !entry.name.includes('node_modules')) { walk(fullPath); } else if (entry.isFile() && entry.name.endsWith(ext)) { @@ -209,7 +221,20 @@ function calculateModuleProgress(moduleDir) { * Check security file status */ function checkSecurityFile(filename, minLines = 100) { + // Validate filename to prevent path traversal + if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) { + return false; + } + const filePath = join(V3_DIR, '@claude-flow/security/src', filename); + + // Additional validation: ensure resolved path is within the expected directory + const resolvedPath = resolve(filePath); + const expectedDir = resolve(join(V3_DIR, '@claude-flow/security/src')); + if (!resolvedPath.startsWith(expectedDir)) { + return false; // Path traversal attempt detected + } + if (!existsSync(filePath)) return false; try {