Skip to content

Security hardening: path validation, input clamping, safe JSON, file locking#19

Merged
colbymchenry merged 2 commits into
mainfrom
security-hardening
Feb 10, 2026
Merged

Security hardening: path validation, input clamping, safe JSON, file locking#19
colbymchenry merged 2 commits into
mainfrom
security-hardening

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Summary

Implements security improvements inspired by PR #16 by @MO2k4. Rather than merging the original PR (which had extensive conflicts against the current codebase), the key ideas were reimplemented fresh.

  • Path traversal prevention: validatePathWithinRoot() utility used in extraction and context building to reject paths that escape the project root
  • MCP input validation: All numeric MCP tool inputs (limit, depth, maxDepth) are clamped to sane ranges
  • Atomic config writes: Config saves use temp file + rename pattern to prevent corrupted configs on crash
  • Symlink cycle detection: Directory scanning tracks visited real paths to prevent infinite loops
  • Safe JSON parsing: All JSON.parse calls in db/queries.ts replaced with safeJsonParse fallbacks for corrupted database metadata
  • Cross-process file locking: FileLock class prevents concurrent DB writes from CLI, MCP server, and git hooks

Test plan

  • Build compiles with no type errors
  • 28 new security tests all passing (__tests__/security.test.ts)
  • Manual test: attempt path traversal via MCP tool inputs
  • Manual test: concurrent indexing from two processes

Credit: @MO2k4 for the security audit and ideas in PR #16

🤖 Generated with Claude Code

colbymchenry and others added 2 commits February 9, 2026 23:18
…locking

Implements security improvements inspired by PR #16 (credit: MO2k4):

- Add validatePathWithinRoot() to prevent path traversal attacks in
  extraction and context building
- Clamp MCP tool inputs (limit, depth, maxDepth) to sane ranges
- Use atomic writes (temp file + rename) for config saves
- Add symlink cycle detection in directory scanning to prevent infinite loops
- Replace all JSON.parse calls in db/queries.ts with safeJsonParse fallbacks
  to handle corrupted database metadata gracefully
- Add cross-process FileLock for DB write operations (indexAll, indexFiles,
  sync) to prevent concurrent writes from CLI, MCP server, and git hooks
- Remove unused path import from context/index.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests cover all security utilities introduced in the previous commit:
- validatePathWithinRoot: path traversal prevention (7 tests)
- safeJsonParse: corrupted JSON fallback handling (6 tests)
- clamp: input range clamping (5 tests)
- FileLock: cross-process file locking (7 tests)
- Atomic config writes: temp file + rename pattern (3 tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@colbymchenry colbymchenry merged commit 082513b into main Feb 10, 2026
colbymchenry added a commit that referenced this pull request Feb 10, 2026
Covers arrow function extraction, best-candidate resolution, graph
traversal direction fix, MCP symbol disambiguation, output truncation,
CLI uninit command, and more. Tests requiring better-sqlite3 native
bindings are conditionally skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@colbymchenry colbymchenry deleted the security-hardening branch February 10, 2026 22:48
fenglibin added a commit to fenglibin/codegraph that referenced this pull request May 25, 2026
将 MCP 工具响应的 staleness footer 从 P0 的盲 30 分钟定时器升级为
git 双信号 4 分支决策:

  hasUncommitted=true            → ⚠️ Uncommitted changes  (最强信号)
  lastCommitTime > maxIndexedAt  → ⚠️ Git has commits newer (次强信号)
  lastCommitTime ≤ maxIndexedAt  → ✓ matches HEAD          (最高可信度)
  lastCommitTime=null (非 git)   → P0 30min 盲计时器(降级,字节兼容)

关键改动:
- src/index.ts: 新增 getProjectChangeSignal() 公共 API,返回
  { lastCommitTime, hasUncommitted };用 git log -1 --format=%ct 取
  committer time(rebase 友好),git status --porcelain
  --untracked-files=normal 取脏状态(自动尊重 .gitignore,覆盖新增
  未 add 文件),并过滤 .codegraph/ 自身目录避免 codegraph 内部工件
  污染信号
- src/mcp/tools.ts: _internal_formatIndexAgeFooter 新增第 3 参
  changeSignal: _internal_ChangeSignal | null = null,4 分支决策;
  ToolHandler.execute() 调用点传入 cg.getProjectChangeSignal()
- src/mcp/server-instructions.ts: rule colbymchenry#5 中英双语扩为 3 种 footer
  字面量识别(uncommitted / git-newer / timer-stale)+ ✓ 高信任标记
- README.md: 核心特性 + 信任信号段升级,宣告 git 项目下 ~100% 检测
  覆盖(修改/新增/删除/改名 无论是否 commit)

P0 兼容性物理保证:
- 9 条 P0/T3 单元测试 0 行修改全过
- 4 条 P0/T3 集成测试 0 行修改全过
- changeSignal=null 时 footer 输出字节兼容 P0
- 第 3 参默认 null 保证向后兼容

测试规模:baseline 835 passing → 853 passing (+18),0 真实 regression。
P0+F-4 共 102 case 100% 通过。剩余 4 个 fail 全部是已知 macOS kqueue
watcher noise(详见 docs/changes/watcher-test-flaky-fix.md)。

4 条漏拦复盘已记录到 changes/0002-p2-f4-smart-stale.md §六:
1. .codegraph/ 内部目录污染 git status(红线 colbymchenry#19 实测才发现)
2. P0/T5 drift guard 需 lockstep 升级(rule 5 文案根本变化)
3. 2nd-commit 集成测试需 sleep 1.1s 推进 committer time
4. 未 commit 警告 vs git-newer 警告优先级哲学决策

方案文档:docs/p2-f4-smart-stale-rationale.md(含 5 候选方案对比 +
风险清单 + 测试设计)
变更记录:changes/0002-p2-f4-smart-stale.md
jorgerobles pushed a commit to jorgerobles/codegraph that referenced this pull request Jun 1, 2026
Security hardening: path validation, input clamping, safe JSON, file locking
jorgerobles pushed a commit to jorgerobles/codegraph that referenced this pull request Jun 1, 2026
Covers arrow function extraction, best-candidate resolution, graph
traversal direction fix, MCP symbol disambiguation, output truncation,
CLI uninit command, and more. Tests requiring better-sqlite3 native
bindings are conditionally skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant