From b22215507f19e3263c17d39944b36c14b6e6436f Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 22 May 2026 20:24:41 +0800 Subject: [PATCH 1/2] fix: remove dead try/catch in insertNode and fix SENSITIVE_PATHS case sensitivity 1. Remove no-op try/catch in QueryBuilder.insertNode() that just re-throws the error without adding any value. 2. Fix SENSITIVE_PATHS case-sensitivity bug on Windows: the Set contained PascalCase entries ('C:\\Windows') but the comparison used resolved.toLowerCase(), which would never match. Normalize all entries to lowercase so the comparison works correctly. --- src/db/queries.ts | 48 ++++++++++++++++++++++------------------------- src/utils.ts | 2 +- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/db/queries.ts b/src/db/queries.ts index fae3b754..9419a313 100644 --- a/src/db/queries.ts +++ b/src/db/queries.ts @@ -230,32 +230,28 @@ export class QueryBuilder { // deleteNode below). this.nodeCache.delete(node.id); - try { - this.stmts.insertNode.run({ - id: node.id, - kind: node.kind, - name: node.name, - qualifiedName: node.qualifiedName ?? node.name, - filePath: node.filePath, - language: node.language, - startLine: node.startLine ?? 0, - endLine: node.endLine ?? 0, - startColumn: node.startColumn ?? 0, - endColumn: node.endColumn ?? 0, - docstring: node.docstring ?? null, - signature: node.signature ?? null, - visibility: node.visibility ?? null, - isExported: node.isExported ? 1 : 0, - isAsync: node.isAsync ? 1 : 0, - isStatic: node.isStatic ? 1 : 0, - isAbstract: node.isAbstract ? 1 : 0, - decorators: node.decorators ? JSON.stringify(node.decorators) : null, - typeParameters: node.typeParameters ? JSON.stringify(node.typeParameters) : null, - updatedAt: node.updatedAt ?? Date.now(), - }); - } catch (error) { - throw error; - } + this.stmts.insertNode.run({ + id: node.id, + kind: node.kind, + name: node.name, + qualifiedName: node.qualifiedName ?? node.name, + filePath: node.filePath, + language: node.language, + startLine: node.startLine ?? 0, + endLine: node.endLine ?? 0, + startColumn: node.startColumn ?? 0, + endColumn: node.endColumn ?? 0, + docstring: node.docstring ?? null, + signature: node.signature ?? null, + visibility: node.visibility ?? null, + isExported: node.isExported ? 1 : 0, + isAsync: node.isAsync ? 1 : 0, + isStatic: node.isStatic ? 1 : 0, + isAbstract: node.isAbstract ? 1 : 0, + decorators: node.decorators ? JSON.stringify(node.decorators) : null, + typeParameters: node.typeParameters ? JSON.stringify(node.typeParameters) : null, + updatedAt: node.updatedAt ?? Date.now(), + }); } /** diff --git a/src/utils.ts b/src/utils.ts index e75e58e0..1ee1c937 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -43,7 +43,7 @@ import * as path from 'path'; const SENSITIVE_PATHS = new Set([ '/', '/etc', '/usr', '/bin', '/sbin', '/var', '/tmp', '/dev', '/proc', '/sys', '/root', '/boot', '/lib', '/lib64', '/opt', - 'C:\\', 'C:\\Windows', 'C:\\Windows\\System32', + 'c:\\', 'c:\\windows', 'c:\\windows\\system32', ]); /** From fefcaaf39eabfcb844c3924ec80e8206b0485752 Mon Sep 17 00:00:00 2001 From: Colby McHenry Date: Fri, 22 May 2026 13:29:07 -0500 Subject: [PATCH 2/2] test: cover validateProjectPath sensitive-directory blocking Adds cross-platform coverage that POSIX system dirs are blocked, that a normal dir is allowed, and a Windows-gated case (C:\Windows vs c:\windows) that locks in the SENSITIVE_PATHS case-insensitivity fix. --- __tests__/security.test.ts | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/__tests__/security.test.ts b/__tests__/security.test.ts index c57158c2..abb70fe6 100644 --- a/__tests__/security.test.ts +++ b/__tests__/security.test.ts @@ -12,7 +12,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { FileLock } from '../src/utils'; +import { FileLock, validateProjectPath } from '../src/utils'; import CodeGraph from '../src/index'; import { ToolHandler, tools } from '../src/mcp/tools'; import { scanDirectory, isSourceFile } from '../src/extraction'; @@ -176,6 +176,36 @@ describe('Path Traversal Prevention', () => { }); }); +describe('validateProjectPath — sensitive directory blocking', () => { + // POSIX-only: on Windows '/etc' resolves to C:\etc (non-existent), not a + // sensitive dir — the Windows case is covered by the win32-gated test below. + it.runIf(process.platform !== 'win32')('blocks POSIX system directories (exact match)', () => { + expect(validateProjectPath('/')).toMatch(/sensitive system directory/i); + expect(validateProjectPath('/etc')).toMatch(/sensitive system directory/i); + }); + + it('allows a normal, existing directory', () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-validate-')); + try { + expect(validateProjectPath(dir)).toBeNull(); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } + }); + + // SENSITIVE_PATHS stores the Windows entries lowercase and validateProjectPath + // matches via resolved.toLowerCase(), so 'C:\\Windows' and 'c:\\windows' are + // both blocked. path.resolve is platform-specific, so this only runs on Windows. + it.runIf(process.platform === 'win32')( + 'blocks Windows system directories regardless of case', + () => { + expect(validateProjectPath('C:\\Windows')).toMatch(/sensitive system directory/i); + expect(validateProjectPath('c:\\windows')).toMatch(/sensitive system directory/i); + expect(validateProjectPath('C:\\WINDOWS\\System32')).toMatch(/sensitive system directory/i); + } + ); +}); + describe('MCP Input Validation', () => { let testDir: string; let cg: CodeGraph;