Skip to content

fix: resolve CodeQL alerts (path injection + workflow token scope)#25

Merged
jhamon merged 4 commits into
mainfrom
fix/codeql-path-injection-and-workflow-permissions
Jul 9, 2026
Merged

fix: resolve CodeQL alerts (path injection + workflow token scope)#25
jhamon merged 4 commits into
mainfrom
fix/codeql-path-injection-and-workflow-permissions

Conversation

@jhamon

@jhamon jhamon commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the open GitHub Code Scanning (CodeQL) alerts on the repo — one real vulnerability and one hardening warning.

1. js/path-injection (error) — server/deleteImage.ts

The DELETE /deleteImage handler passed the client-supplied imagePath query param straight into fs.rename(imagePath, …). A caller could send imagePath=../../something and rename files anywhere the server process can write, outside the intended data/ directory.

Fix: resolve the path and verify it stays inside data/ before any filesystem access, then rename using the confined absolute path. The Pinecone lookup still uses the original stored relative path (that's the value in the vector metadata), so search/delete behavior is unchanged for legitimate paths.

2. actions/missing-workflow-permissions (warning) — .github/workflows/test.yml

The workflow didn't declare a permissions: block, so GITHUB_TOKEN got the broad default scope. Added permissions: contents: read at the top level; both jobs only check out and test.

Testing

  • Added a test asserting a traversal path (../../etc/passwd) is rejected before touching disk or Pinecone.
  • Updated the existing deleteImage test to expect the resolved absolute path.
  • npm run lint, npm run typecheck, and full npm run test:server (43 tests incl. live e2e delete) all pass.

🤖 Generated with Claude Code

Resolves the open CodeQL alerts on the repo:

- js/path-injection (error): /deleteImage passed the client-supplied
  `imagePath` query param straight into `fs.rename`, so a value like
  "../../etc/passwd" could rename files outside the data directory.
  Resolve the path and verify it stays within data/ before any fs use,
  passing the confined absolute path to `fs.rename`.

- actions/missing-workflow-permissions (warning): add a top-level
  `permissions: contents: read` block to the Test workflow so the
  GITHUB_TOKEN is narrowed from its broad default.

Adds a test covering the traversal-rejection path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread server/deleteImage.ts Fixed
Comment thread server/deleteImage.ts Fixed
jhamon and others added 3 commits July 9, 2026 11:13
Apply the same data-directory confinement to the /search handler, whose
client-supplied `imagePath` was read by the embedder. Extract the
resolveWithinDataDir guard into utils/util.ts so deleteImage and query
share one implementation, and cover the search traversal-rejection path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CodeQL still flagged js/path-injection because it only recognizes the
data-directory check as a sanitizer when the guard is in the same
function as the sink; the shared resolveWithinDataDir helper put it
behind a function return, so the barrier didn't transfer.

Inline the resolve-and-prefix-check guard directly in deleteImage and
queryImages, keeping only DATA_DIR shared in utils/util.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The startsWith(DATA_DIR + path.sep) guard wasn't accepted by CodeQL's
path-injection sanitizer recognition. Switch to the documented idiom —
reject when path.relative(DATA_DIR, resolved) starts with ".." — which
CodeQL treats as a path-traversal barrier. Semantics are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jhamon jhamon merged commit b5f236a into main Jul 9, 2026
6 checks passed
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