Skip to content

Fix npm dependency-confusion bug in MCP server default command - #4

Merged
RudrenduPaul merged 1 commit into
mainfrom
fix/security-audit-2026-08-24
Aug 25, 2026
Merged

Fix npm dependency-confusion bug in MCP server default command#4
RudrenduPaul merged 1 commit into
mainfrom
fix/security-audit-2026-08-24

Conversation

@Sourav-Nandy-ai

Copy link
Copy Markdown
Collaborator

Summary

  • HIGH: npm dependency confusion. python/src/graphkeeper/mcp_server.py defaulted to running npx graphkeeper (missing the -cli suffix) whenever GRAPHKEEPER_CLI_JS was unset. The project's actual published npm package is graphkeeper-cli; the bare name graphkeeper is a completely unrelated, unaudited third-party package (graphkeeper@0.4.1, published by a different maintainer, anusbutt). Anyone following the documented MCP setup without a local-dev override would have silently installed and run that unrelated package's code instead of this project's CLI. Fixed the default command, updated the surrounding docstrings/comments to warn against dropping the -cli suffix, corrected the one stale prose reference in README.md's MCP section, and added python/tests/test_mcp_server.py to regression-test the exact command string.
  • Windows-specific bugs in normalize_file_arg (python/src/graphkeeper/query.py). Compared against the TypeScript original (src/query.ts), the Python port had two Windows-only bugs: (1) os.path.isabs returns False for POSIX-style root-relative paths like /repo/src/a.py on Windows (unlike Node's path.isAbsolute, which returns True), so the port silently skipped relativizing exactly the kind of absolute path an MCP client is likely to pass; (2) os.path.relpath raises ValueError when the file argument and the repo path are on different drives (e.g. repo on C:, file on D:), unlike path.relative, which just returns the path unchanged in that case -- this crashed the query instead of degrading gracefully. Added a _is_absolute helper matching Node's semantics and wrapped relpath to fall back to the TS behavior on ValueError. Added regression tests in python/tests/test_query.py.
  • LOW: mutable-tag GitHub Actions. .github/workflows/codeql.yml referenced actions/checkout@v4 and github/codeql-action/{init,autobuild,analyze}@v3 by mutable tag. SHA-pinned all four to match the pinning style already used in publish-pypi.yml.

Test plan

  • python -m pytest tests/ (from python/): 82 passed, 3 failed -- the 3 failures are pre-existing and unrelated to this change (OSError: [WinError 1314], Windows requires elevated privilege/Developer Mode to create symlinks via os.symlink; these tests exercise symlink-based path-traversal safety and fail identically on main).
  • npm run typecheck: clean.
  • npm test (vitest): 75 passed, 3 failed -- same pre-existing Windows symlink-privilege limitation on the TS side (EPERM: operation not permitted, symlink), not caused by this change (no src/*.ts files were touched).

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01QyJoCc6YtjnErv6HKa6NPu

python/src/graphkeeper/mcp_server.py defaulted to running `npx graphkeeper`
(missing the `-cli` suffix) when no local-dev override was set. The
published npm package for this project is `graphkeeper-cli`; the bare
name `graphkeeper` resolves to a completely unrelated, unaudited
third-party package by a different maintainer. Anyone following the
documented MCP setup without GRAPHKEEPER_CLI_JS set would have silently
installed and executed that unrelated package instead of this project's
CLI.

- python/src/graphkeeper/mcp_server.py: default command and docstrings
  now reference `graphkeeper-cli`, with an explicit warning against
  dropping the `-cli` suffix.
- README.md: corrected the MCP section's prose reference to the
  underlying npm package name.
- python/tests/test_mcp_server.py: new regression tests asserting the
  default command is `[npx, graphkeeper-cli]` and never contains the
  bare `graphkeeper` name.

Also fixes two more issues found in a fresh audit pass:

- python/src/graphkeeper/query.py: `normalize_file_arg` had two
  Windows-specific bugs versus the TypeScript original (src/query.ts):
  (1) `os.path.isabs` returns False for POSIX-style root-relative paths
  like /repo/src/a.py on Windows, unlike Node's `path.isAbsolute`,
  silently skipping relativization; (2) `os.path.relpath` raises
  ValueError when the file arg and repo path are on different drives,
  unlike `path.relative`, which crashed the query. Added `_is_absolute`
  to match Node's semantics and a try/except around `relpath` that falls
  back to leaving the path unchanged, matching the TS behavior. Added
  regression tests in test_query.py.
- .github/workflows/codeql.yml: SHA-pinned actions/checkout and the
  github/codeql-action init/autobuild/analyze steps, which were on
  mutable version tags.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QyJoCc6YtjnErv6HKa6NPu
@RudrenduPaul
RudrenduPaul merged commit 2a025f1 into main Aug 25, 2026
3 checks passed
@RudrenduPaul
RudrenduPaul deleted the fix/security-audit-2026-08-24 branch August 25, 2026 15:44
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.

2 participants