Root cause
Injection & unsafe execution introduced
Swap ScrapeJobEntry ick for Websites/WebsitePages, add Logs to Resources
AI-assisted change: Claude
How AI contributed: Direct introductionPublished Apr 30, 2026 in
zachhandley/zmcptools
Path traversal in the MCP Log Resource Handler (src/managers/ResourceManager.ts): resource templates logs://{dirname}/files and logs://{dirname}/content build paths via path.join(homedir(), '.mcptools', 'logs', dirname[, filename]) with no traversal containment check, so an attacker-controlled dirname (and the file query param) can escape ~/.mcptools/logs to list (readdir/stat) and read (readFile) arbitrary files (e.g. ../../../../etc/passwd). Exposed over MCP resources; remote exploitation possible; CVSS 6.3.
Root cause
Swap ScrapeJobEntry ick for Websites/WebsitePages, add Logs to Resources
AI-assisted change: Claude
Fix status
No minimum fix commit has been established for this finding.
Fix status unresolved
Case facts
@@ -6,7 +6,12 @@ import { WebScrapingService } from '../services/WebScrapingService.js'; import { DocumentationService } from '../services/DocumentationService.js'; import { MemoryService } from '../services/MemoryService.js'; import { VectorSearchService } from '../services/VectorSearchService.js';+import { WebsiteRepository } from '../repositories/WebsiteRepository.js';+import { WebsitePagesRepository } from '../repositories/WebsitePagesRepository.js'; import { PathUtils } from '../utils/pathUtils.js';+import { readdir, stat, readFile } from 'fs/promises';+import { join } from 'path';+import { homedir } from 'os'; export interface ResourceInfo { uri: string;@@ -23,6 +28,8 @@ export class ResourceManager { private documentationService: DocumentationService; private memoryService: MemoryService; private vectorSearchService: VectorSearchService;+ private websiteRepository: WebsiteRepository;+ private websitePagesRepository: WebsitePagesRepository; constructor( private db: DatabaseManager,@@ -42,6 +49,8 @@ export class ResourceManager { ); this.documentationService = new DocumentationService(this.db); this.vectorSearchService = new VectorSearchService(this.db);+ this.websiteRepository = new WebsiteRepository(this.db);+ this.websitePagesRepository = new WebsitePagesRepository(this.db); } /**@@ -52,13 +61,13 @@ export class ResourceManager { { uri: 'agents://list', name: 'Agent List',- description: 'List of all active agents with their status and metadata',+ description: 'List of all active agents with their status and metadata (use ?limit=50&offset=0&status=active&type=backend)', mimeType: 'application/json' }, { uri: 'communication://rooms', name: 'Communication Rooms',- description: 'List of all active communication rooms',+ description: 'List of all active communication rooms (use ?limit=50&offset=0&search=text)', mimeType: 'application/json' }, {@@ -70,25 +79,37 @@ export class ResourceManager { { uri: 'scraping://jobs', name: 'Scraper Jobs',- description: 'List of web scraping jobs and their status',+ description: 'List of web scraping jobs and their status (use ?limit=50&offset=0&status=active&search=text)', mimeType: 'application/json' }, { uri: 'documentation://sources', name: 'Documentation Sources',- description: 'List of scraped documentation sources',+ description: 'List of scraped documentation sources (use ?limit=50&offset=0&sourceType=api&search=text)',+ mimeType: 'application/json'+ },+ {+ uri: 'documentation://websites',+ name: 'Documentation Websites',+ description: 'List of all scraped websites (use ?limit=50&offset=0&search=text)',+ mimeType: 'application/json'+ },+ {+ uri: 'documentation://*/pages',+ name: 'Website Pages',+ description: 'List of pages for a specific website (use documentation://{websiteId}/pages?limit=50&offset=0&search=text)', mimeType: 'application/json' }, { uri: 'agents://insights', name: 'Agent Insights',- description: 'Aggregated insights and learnings from agents',+ description: 'Aggregated insights and learnings from agents (use ?limit=100&offset=0&memoryType=insight&agentId=id&search=text)', mimeType: 'application/json' }, { uri: 'vector://collections', name: 'Vector Collections',- description: 'List of ChromaDB vector collections and their statistics',+ description: 'List of ChromaDB vector collections and their statistics (use ?limit=50&offset=0&search=text)', mimeType: 'application/json' }, {@@ -102,6 +123,24 @@ export class ResourceManager {@@ -7,6 +7,7 @@ import type { ClaudeSpawnConfig } from '../process/ClaudeSpawner.js'; import { Logger } from '../utils/logger.js'; import { AgentPermissionManager } from '../utils/agentPermissions.js'; import { PathUtils } from '../utils/pathUtils.js';+import { FoundationCacheService } from './FoundationCacheService.js'; import { eq, and } from 'drizzle-orm'; import { agentSessions } from '../schemas/index.js'; import { resolve } from 'path';@@ -388,10 +389,36 @@ export class AgentService { disallowedTools = agent.toolPermissions.disallowedTools; } + // 🚀 AUTOMATIC FOUNDATION CACHING INTEGRATION+ // Get or create foundation session for 85-90% token cost reduction+ let foundationSessionId: string | undefined;+ + if (this.shouldUseFoundationCaching(agent)) {+ try {+ const cacheService = new FoundationCacheService(this.db);+ foundationSessionId = await cacheService.getOrCreateFoundationSession(+ workingDirectory,+ this.generateAgentContext(agent, taskDescription)+ );+ + this.logger.info('Foundation session auto-created for agent', {+ agentId: agent.id,+ foundationSessionId,+ repositoryPath: workingDirectory,+ tokenSavings: '85-90% expected'+ });+ } catch (error) {+ this.logger.warn('Failed to create foundation session, continuing without caching', {+ agentId: agent.id,+ error: error instanceof Error ? error.message : String(error)+ });+ }+ }+ const config: ClaudeSpawnConfig = { workingDirectory, prompt,- sessionId: `agent_${agent.id}`,+ sessionId: foundationSessionId || `agent_${agent.id}`, // Use foundation session if available capabilities: agent.capabilities, allowedTools: allowedTools, disallowedTools: disallowedTools,@@ -401,7 +428,8 @@ export class AgentService { AGENT_TYPE: agent.agentType || 'general_agent', TASK_DESCRIPTION: taskDescription, REPOSITORY_PATH: workingDirectory,- ROOM_ID: agent.roomId || ''+ ROOM_ID: agent.roomId || '',+ FOUNDATION_SESSION_ID: foundationSessionId || '' }, ...claudeConfig };@@ -749,4 +777,36 @@ Focus on successfully completing your assigned task using your specialized capab checkCompletion(); }); }++ // 🚀 FOUNDATION CACHING HELPER METHODS+ + /**+ * Determines if an agent should use foundation caching+ * Enables for all agents by default, with opt-out capability+ */+ private shouldUseFoundationCaching(agent: AgentSession): boolean {+ // Allow opt-out via metadata+ if (agent.agentMetadata?.disableFoundationCaching === true) {+ return false;+ }+ + // Enable for all agents by default+ return true;+ }+ + /**+ * Generates context for foundation caching session+ */+ private generateAgentContext(agent: AgentSession, taskDescription: string): any {+ return {+ agentId: agent.id,+ agentName: agent.agentName,+ agentType: agent.agentType,+ taskDescription,+ capabilities: agent.capabilities,+ repositoryPath: agent.repositoryPath,+ timestamp: new Date().toISOString(),+ toolPermissions: agent.toolPermissions@@ -26,7 +26,7 @@ import { BrowserMcpTools } from '../tools/BrowserMcpTools.js'; import { WebScrapingMcpTools } from '../tools/WebScrapingMcpTools.js'; import { AnalysisMcpTools } from '../tools/AnalysisMcpTools.js'; import { TreeSummaryTools } from '../tools/TreeSummaryTools.js';-import { CacheMcpTools } from '../tools/CacheMcpTools.js';+// CacheMcpTools removed - foundation caching now automatic import { BrowserTools } from '../tools/BrowserTools.js'; import { WebScrapingService } from '../services/WebScrapingService.js'; import { AgentService, MemoryService, FileOperationsService, TreeSummaryService, fileOperationsService } from '../services/index.js';@@ -51,7 +51,7 @@ export class McpServer { private webScrapingMcpTools: WebScrapingMcpTools; private analysisMcpTools: AnalysisMcpTools; private treeSummaryTools: TreeSummaryTools;- private cacheMcpTools: CacheMcpTools;+ // cacheMcpTools removed - foundation caching now automatic private fileOperationsService: FileOperationsService; private treeSummaryService: TreeSummaryService; private resourceManager: ResourceManager;@@ -113,7 +113,7 @@ export class McpServer { this.webScrapingMcpTools = new WebScrapingMcpTools(webScrapingService, memoryService, this.repositoryPath); this.analysisMcpTools = new AnalysisMcpTools(memoryService, this.repositoryPath); this.treeSummaryTools = new TreeSummaryTools();- this.cacheMcpTools = new CacheMcpTools(this.db);+ // Foundation caching is now automatic - no manual tools needed // Initialize managers this.resourceManager = new ResourceManager(this.db, this.repositoryPath);@@ -249,9 +249,8 @@ export class McpServer { // Analysis and file operation tools ...this.analysisMcpTools.getTools(), // TreeSummary tools- ...this.treeSummaryTools.getTools(),- // Foundation Cache tools- ...this.cacheMcpTools.getTools()+ ...this.treeSummaryTools.getTools()+ // Foundation Cache tools removed - now automatic ]; } @@ -652,11 +651,7 @@ export class McpServer { return await this.treeSummaryTools.handleToolCall(name, args); } - // Check Foundation Cache tools- const cacheToolNames = this.cacheMcpTools.getTools().map(t => t.name);- if (cacheToolNames.includes(name)) {- return await this.cacheMcpTools.handleToolCall(name, args);- }+ // Foundation Cache tools removed - now automatic // Handle orchestration tools switch (name) {