Skip to content

fix: validate reviewAgentLogPath to prevent path injection#1134

Merged
msukkari merged 9 commits intomainfrom
cursor/fix-path-injection-codeql-05f4
Apr 18, 2026
Merged

fix: validate reviewAgentLogPath to prevent path injection#1134
msukkari merged 9 commits intomainfrom
cursor/fix-path-injection-codeql-05f4

Conversation

@msukkari
Copy link
Copy Markdown
Contributor

@msukkari msukkari commented Apr 18, 2026

Fixes SOU-930

Summary

This PR addresses CodeQL alert #19 (js/path-injection) by adding path validation to the invokeDiffReviewLlm function in the review agent.

Problem

The reviewAgentLogPath parameter was passed to fs.appendFileSync without validation, creating a latent path injection vulnerability. While the current code constructs the path safely using pullRequest.number (which is always an integer from the GitHub API), the function itself did not validate the path, meaning any future changes to the call chain could introduce a security issue.

Solution

Added a validateLogPath helper function that:

  1. Resolves the provided path to an absolute path
  2. Verifies the resolved path starts with the expected base directory (DATA_CACHE_DIR/review-agent/)
  3. Throws an error if the path attempts to escape the log directory

The validation is performed before each fs.appendFileSync call to ensure defense-in-depth.

Additionally, the log directory constant is now exported from invokeDiffReviewLlm.ts and shared with app.ts to ensure a single source of truth.

Changes

  • Added path import to invokeDiffReviewLlm.ts
  • Added exported REVIEW_AGENT_LOG_DIR constant for the expected log directory
  • Added validateLogPath() helper function that validates paths are within the expected directory
  • Applied validation before both fs.appendFileSync calls (prompt and response logging)
  • Updated app.ts to import and use REVIEW_AGENT_LOG_DIR instead of defining it locally

Testing

  • All existing tests pass
  • Build compiles successfully
  • Lint checks pass

References

Linear Issue: SOU-930

Open in Web Open in Cursor 

Summary by CodeRabbit

  • Bug Fixes

    • Ensured the review agent can only write logs inside its designated log directory; added path validation to prevent writing outside that directory.
    • Logged a changelog "Fixed" entry documenting the path validation for review-agent log writing.
  • Documentation

    • Updated PR description guidelines to auto-link Linear issues when a Linear ID is provided.

Add path validation to invokeDiffReviewLlm to ensure the log path
stays within the expected DATA_CACHE_DIR/review-agent directory.
This addresses CodeQL alert #19 (js/path-injection) by resolving
the path and verifying it does not escape the log directory.

The validation is performed before each fs.appendFileSync call
to prevent path traversal attacks even if the call chain changes
in the future.

Co-authored-by: Michael Sukkarieh <msukkari@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e3ba9f07-a159-4621-bcef-2b89c15a0298

📥 Commits

Reviewing files that changed from the base of the PR and between 154b096 and 3ed9937.

📒 Files selected for processing (1)
  • CHANGELOG.md
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

Walkthrough

Log path handling for the review agent was hardened: log directory resolution was centralized via getReviewAgentLogDir(), and reviewAgentLogPath values are resolved and validated to prevent directory traversal before writing prompts or LLM responses. CHANGELOG and PR guidelines were also updated.

Changes

Cohort / File(s) Summary
Review agent logging & validation
packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts
Added and exported getReviewAgentLogDir() and validateLogPath(); resolve and validate reviewAgentLogPath before writing prompt and before writing OpenAI response to prevent path traversal.
Log directory usage
packages/web/src/features/agents/review-agent/app.ts
Replaced inline path.join(env.DATA_CACHE_DIR, "review-agent") with getReviewAgentLogDir() for existence check, recursive creation, and timestamped log path generation.
Changelog
CHANGELOG.md
Added an “[Unreleased] → Fixed” entry documenting the path injection fix in the review agent’s log writing flow.
Docs – PR guidelines
CLAUDE.md
Updated PR description guidance to require adding Fixes <LinearIssueID> at the top when a Linear issue ID is provided.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Proc as processGitHubPullRequest
  participant App as app.ts
  participant Agent as invokeDiffReviewLlm
  participant FS as Filesystem
  participant LLM as OpenAI

  Proc->>App: start processing PR
  App->>Agent: call process with PR data
  Agent->>Agent: dir = getReviewAgentLogDir()
  Agent->>FS: resolve(proposedLogPath)
  Agent->>Agent: validateLogPath(resolvedPath, dir)
  Agent->>FS: write prompt file (validated path)
  Agent->>LLM: send prompt -> await response
  LLM-->>Agent: response
  Agent->>FS: resolve(responseLogPath)
  Agent->>Agent: validateLogPath(resolvedResponsePath, dir)
  Agent->>FS: write response file (validated path)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly matches the main security fix: validating reviewAgentLogPath to prevent path injection vulnerability.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/fix-path-injection-codeql-05f4

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

cursoragent and others added 2 commits April 18, 2026 01:57
Co-authored-by: Michael Sukkarieh <msukkari@users.noreply.github.com>
…keDiffReviewLlm.ts

Export the log directory constant from invokeDiffReviewLlm.ts and
import it in app.ts to ensure a single source of truth for the
review agent log directory path.

Co-authored-by: Michael Sukkarieh <msukkari@users.noreply.github.com>
@msukkari msukkari marked this pull request as ready for review April 18, 2026 02:04
Co-authored-by: Michael Sukkarieh <msukkari@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts (1)

31-48: Minor: redundant double validation.

reviewAgentLogPath is a function parameter (a string) that doesn't change between the two validateLogPath calls, so the second invocation on Line 46 is redundant. Validating once near the top of invokeDiffReviewLlm (when reviewAgentLogPath is defined) would be simpler and still safe — there's no TOCTOU benefit here since the check is purely string-based.

♻️ Proposed refactor
     if (!env.OPENAI_API_KEY) {
         logger.error("OPENAI_API_KEY is not set, skipping review agent");
         throw new Error("OPENAI_API_KEY is not set, skipping review agent");
     }
+
+    if (reviewAgentLogPath) {
+        validateLogPath(reviewAgentLogPath);
+    }
     
     const openai = new OpenAI({
         apiKey: env.OPENAI_API_KEY,
     });
 
     if (reviewAgentLogPath) {
-        validateLogPath(reviewAgentLogPath);
         fs.appendFileSync(reviewAgentLogPath, `\n\nPrompt:\n${prompt}`);
     }
@@
         if (reviewAgentLogPath) {
-            validateLogPath(reviewAgentLogPath);
             fs.appendFileSync(reviewAgentLogPath, `\n\nResponse:\n${openaiResponse}`);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts`
around lines 31 - 48, The code calls validateLogPath(reviewAgentLogPath) twice
inside invokeDiffReviewLlm — once before appending the prompt and again before
appending the response — which is redundant because reviewAgentLogPath is an
immutable parameter; remove the second call. Update invokeDiffReviewLlm to
validate reviewAgentLogPath once (when reviewAgentLogPath is truthy) before the
first fs.appendFileSync, and keep the subsequent
fs.appendFileSync(reviewAgentLogPath, `\n\nResponse:\n${openaiResponse}`)
without re-validating; reference validateLogPath, reviewAgentLogPath,
invokeDiffReviewLlm, and fs.appendFileSync to locate the lines to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts`:
- Around line 10-17: Make REVIEW_AGENT_LOG_DIR an absolute canonical path by
using path.resolve on env.DATA_CACHE_DIR (e.g., REVIEW_AGENT_LOG_DIR =
path.resolve(env.DATA_CACHE_DIR, 'review-agent')), and update validateLogPath to
canonicalize both the base and the incoming logPath (use path.resolve) then
compute const rel = path.relative(REVIEW_AGENT_LOG_DIR, resolved); reject the
path when rel is empty, is absolute (path.isAbsolute(rel)), or startsWith('..')
and throw the existing error; reference symbols: REVIEW_AGENT_LOG_DIR and
validateLogPath.

---

Nitpick comments:
In `@packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts`:
- Around line 31-48: The code calls validateLogPath(reviewAgentLogPath) twice
inside invokeDiffReviewLlm — once before appending the prompt and again before
appending the response — which is redundant because reviewAgentLogPath is an
immutable parameter; remove the second call. Update invokeDiffReviewLlm to
validate reviewAgentLogPath once (when reviewAgentLogPath is truthy) before the
first fs.appendFileSync, and keep the subsequent
fs.appendFileSync(reviewAgentLogPath, `\n\nResponse:\n${openaiResponse}`)
without re-validating; reference validateLogPath, reviewAgentLogPath,
invokeDiffReviewLlm, and fs.appendFileSync to locate the lines to change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d34658fd-f05a-4b07-abcf-0440067a55bf

📥 Commits

Reviewing files that changed from the base of the PR and between 2c89825 and 9b6e216.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • packages/web/src/features/agents/review-agent/app.ts
  • packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts

Comment thread packages/web/src/features/agents/review-agent/nodes/invokeDiffReviewLlm.ts Outdated
@msukkari
Copy link
Copy Markdown
Contributor Author

test

cursoragent and others added 5 commits April 18, 2026 02:28
Change REVIEW_AGENT_LOG_DIR from a top-level constant to a
getReviewAgentLogDir() function to avoid evaluating env.DATA_CACHE_DIR
at module load time, which fails during Next.js build when
environment variables are not yet available.

Co-authored-by: Michael Sukkarieh <msukkari@users.noreply.github.com>
Co-authored-by: Michael Sukkarieh <msukkari@users.noreply.github.com>
@msukkari msukkari merged commit ddea515 into main Apr 18, 2026
8 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