fix(agent): address CodeRabbit findings on direct-call dispatch (#4891)#4905
fix(agent): address CodeRabbit findings on direct-call dispatch (#4891)#4905mmabrouk wants to merge 1 commit into
Conversation
Follow-up to PR #4891 (direct-call tools, Phase 2 sidecar dispatch). The CodeRabbit review that ran after the hardening commit posted five actionable findings that landed unaddressed when the PR merged. This addresses them in services/agent/src/tools/direct.ts. - Sanitize nested prototype-polluting keys. deepMerge now recurses into every plain-object value (onto a fresh subtree when the base side is not an object), so a nested __proto__/constructor/prototype inside an untrusted subtree can no longer be assigned wholesale. assembleBody deep-sanitizes the model args (untrusted) before they land at args_into or the root, instead of a bare spread. - Fail closed when the callback mount cannot be derived. directCallUrl normalizes a trailing slash, then rejects any callback path that does not end with /tools/call rather than deriving an empty mount that silently widens the SSRF guard to any same-origin path. - Stop logging the upstream response body. callDirect no longer reads or logs the upstream body on the error path (it can carry user data); it keeps the run's own internal URL and the status, which are load-bearing for diagnosis and carry no credentials. - Fail fast on a GET with a non-empty body. fetch forbids a GET body, so an assembled body on a GET descriptor would be silently dropped; callDirect now throws instead of executing a call that loses its inputs. - Refresh the test header: relay-only (dispatch branch deferred), mount-agnostic path rule. Adds coverage for nested-key sanitization, fail-closed mount derivation, and the GET-with-body guard. Runner typecheck clean; 316 vitest tests pass. Claude-Session: https://claude.ai/code/session_01GYo3UEfvsZpncagqb28Mbc
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThree security hardening changes to Direct-call tool security hardening
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
🤖 The AI agent says: What this needs from you: a review of how I triaged CodeRabbit's five findings on the merged #4891, and confirmation on the two judgment calls below. This is the follow-up the task asked for: #4891 merged with CodeRabbit's post-hardening review (five actionable findings) unaddressed. I fixed all five in Two calls I want you to sanity-check:
The shallow fixed-wins overlay (sibling-key) stays deferred exactly as you noted on #4891 — that needs request-schema enforcement, a separate change. The prototype-pollution sanitization here is distinct and fully fixed. Checks: runner |
|
@coderabbitai review |
✅ Action performedReview finished.
|
Why
PR #4891 (direct-call tools, Phase 2 sidecar dispatch) was merged with a green lgtm, but the CodeRabbit review that ran right after the hardening commit posted five actionable findings that never got folded in before the merge. This PR addresses all five in
services/agent/src/tools/direct.ts, with tests.The wire is unchanged and no resolver emits a
calldescriptor yet, so production behavior does not change. These are guard hardenings plus one functional-correctness trap.What changed
deepMergenow recurses into every plain-object value, so a nested__proto__/constructor/prototypeinside an untrusted subtree is stripped at every level.assembleBodydeep-sanitizes the model args before they land atargs_intoor the root.directCallUrlnormalizes a trailing slash, then fails closed (throws) on any callback path that does not end with/tools/call, instead of deriving an empty mount.callDirectno longer reads or logs the upstream response body on the error path. It keeps the run's own internal URL and the status (no credentials; the authorization header is never logged), which are load-bearing for diagnosis.GETdirect call silently drops model argscallDirectfails fast when aGETcarries a non-empty assembled body, instead of executing a call that quietly loses its inputs.dispatch.tsbranch and an/api-relative rule)Before / after (finding 3, server log on a non-2xx)
Before:
After:
Tests
Added coverage for nested-key sanitization (
assembleBody+deepMerge), fail-closed mount derivation (and trailing-slash normalization), and theGET-with-body guard.cd services/agent && pnpm typecheckclean.pnpm testgreen: 316 tests across 31 files.Not in this PR
The shallow fixed-wins overlay (a model can add a sibling key under a subtree that
call.bodyonly partly fixes) stays deferred, as noted on #4891. The durable fix there is strict request-schema enforcement on the assembled body, which is a larger, separate change. The prototype-pollution sanitization in this PR is distinct from that and is fully addressed.https://claude.ai/code/session_01GYo3UEfvsZpncagqb28Mbc