Skip to content

fix(agent-sdk): pass settingSources [] so SDK ignores cloned PR .claude/settings.json#195

Merged
chrisleekr merged 1 commit into
mainfrom
fix/issue-191
May 31, 2026
Merged

fix(agent-sdk): pass settingSources [] so SDK ignores cloned PR .claude/settings.json#195
chrisleekr merged 1 commit into
mainfrom
fix/issue-191

Conversation

@chrisleekr
Copy link
Copy Markdown
Owner

@chrisleekr chrisleekr commented May 31, 2026

Summary

Closes #191.

The Claude Agent SDK query() runs with cwd set to the cloned PR working tree (src/core/checkout.ts clones the PR head into workDir, and src/core/executor.ts passes cwd: workDir) but never passed settingSources. Per the SDK contract (SettingSource = 'user' | 'project' | 'local', node_modules/@anthropic-ai/claude-agent-sdk/sdk.d.ts), omitting it loads all three filesystem tiers by default.

Attack path closed

A fork PR from any GitHub user can ship a hostile .claude/settings.json with a SessionStart shell hook. The webhook router (src/webhook/router.ts) gates on ALLOWED_OWNERS, not PR author, so any maintainer comment triggers the bot on that PR. The hook fires in the CLI subprocess — which carries GH_TOKEN/GITHUB_TOKEN (App installation token) and ANTHROPIC_* creds in env — before any tool gate, bypassing every existing prompt-injection defense. This is a credential-exfil / RCE path against the daemon.

Fix

Pin settingSources: [] in the queryOptions object (src/core/executor.ts, beside the existing disallowedTools: ["ToolSearch"] idiom). This disables the user/project/local filesystem tiers, so a hostile .claude/settings.json is never loaded. The managed-settings policy tier (operator-controlled, outside the cloned tree) is unaffected.

Changes

  • src/core/executor.ts — add settingSources: [] + comment documenting the attack path and a regression warning.
  • test/core/executor.test.ts — new executeAgent: filesystem settings isolation test asserting options.settingSources deep-equals [] (catches both removal and a flip to a permissive value like ["user"]).

Verification

  • New test is red without the fix (Expected: [] / Received: undefined), green with it.
  • Executor suite: 18 pass / 0 fail (via scripts/test-isolated.sh harness). Typecheck clean; prettier clean; no em-dash.

Deferred (defense-in-depth follow-ups, out of scope here)

Per the issue's suggested next steps 2/4/5: a CLAUDE.md security-invariant bullet, removing .claude/ from workDir after checkout, and a periodic SDK call-site audit. These reduce the broader "untrusted tree at cwd" surface but are not required to close #191.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Agent subprocess configuration handling updated to explicitly exclude user-level, project-level, and local filesystem settings sources during query execution, while preserving existing behavior for prompt selection, tool configuration, environment handling, and timeout management.
  • Tests

    • Added new test suite to verify that agent subprocess properly isolates configuration sources and correctly excludes local filesystem configuration files.

…de/settings.json

The Agent SDK query() runs with cwd set to the cloned PR working tree but
never passed settingSources, so the SDK loaded user/project/local filesystem
settings (.claude/settings.json) by default. A hostile fork PR could ship a
.claude/settings.json with a SessionStart shell hook that fires in the CLI
subprocess (which carries GH_TOKEN/GITHUB_TOKEN and ANTHROPIC creds in env)
before any tool gate, enabling credential exfiltration / RCE.

Pin settingSources to [] to disable all three filesystem tiers. Adds a
regression test asserting options.settingSources deep-equals [] (catches both
removal and a flip to a permissive value).

Defense-in-depth follow-ups (rm .claude/ from workDir, CLAUDE.md invariant
bullet, call-site audit) are deferred.

Closes #191

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 31, 2026 16:18
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 13422501-cc05-4c6e-bf68-7708d5639209

📥 Commits

Reviewing files that changed from the base of the PR and between 978abd2 and 115a5e6.

📒 Files selected for processing (2)
  • src/core/executor.ts
  • test/core/executor.test.ts

📝 Walkthrough

Walkthrough

This PR hardens the Claude Agent SDK invocation in executeAgent by explicitly disabling filesystem-based settings loading. The change adds settingSources: [] to prevent the SDK from reading potentially attacker-controlled .claude/settings.json from cloned PR content. A test validates the parameter is set correctly.

Changes

Filesystem Settings Isolation

Layer / File(s) Summary
settingSources empty-array security hardening
src/core/executor.ts, test/core/executor.test.ts
queryOptions.settingSources is set to an empty array to block the Claude Agent SDK's default loading of user, project, and local filesystem settings from cwd (the cloned PR working directory). A new test suite asserts that executeAgent passes settingSources: [] into the SDK query options, preventing SessionStart shell hooks from executing in a subprocess that has installation token credentials.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Suggested labels

type: fix 🐞

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the core security fix: passing settingSources [] to prevent the SDK from loading potentially attacker-controlled .claude/settings.json from the cloned PR repository.
Linked Issues check ✅ Passed The pull request fully addresses issue #191's primary objective: settingSources [] is added to queryOptions in executor.ts with documentation, and a regression-preventing test asserting deep equality to [] is added in the test suite.
Out of Scope Changes check ✅ Passed All changes are tightly scoped to issue #191's core requirement. The pull request explicitly defers related but separate mitigations (CLAUDE.md security invariant, .claude/ removal, SDK audit) as out of scope.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Hardens the Claude Agent SDK call site by explicitly setting settingSources: [] so the SDK does not load .claude/settings.json (or user/local equivalents) from the cloned PR working tree, which could otherwise execute attacker-controlled SessionStart shell hooks with the GitHub App installation token in env.

Changes:

  • Add settingSources: [] to queryOptions in src/core/executor.ts with an inline comment documenting the attack path and regression warning.
  • Add a regression test in test/core/executor.test.ts asserting deep equality of options.settingSources to [].

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/core/executor.ts Pins settingSources: [] next to existing disallowedTools hardening to block filesystem-tier settings loading from cwd.
test/core/executor.test.ts New test verifying the queryOptions deep-equals [] for settingSources, catching both removal and permissive flips.

@chrisleekr chrisleekr merged commit 153fef3 into main May 31, 2026
23 checks passed
@chrisleekr chrisleekr deleted the fix/issue-191 branch May 31, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security(agent-sdk): SDK loads .claude/settings.json from cloned PR cwd; pass settingSources []

2 participants