Add prototype pollution guard to resolveConfigPath - #59694
vincentkoc merged 2 commits into
Conversation
Greptile SummaryThis PR adds a prototype pollution guard to
Confidence Score: 5/5
Reviews (1): Last reviewed commit: "Add prototype pollution guard to resolve..." | Re-trigger Greptile |
|
Codex review: needs maintainer review before merge. Reviewed June 28, 2026, 4:42 PM ET / 20:42 UTC. Summary PR surface: Source +15, Tests +19. Total +34 across 2 files. Reproducibility: yes. Source inspection shows current main indexes raw dotted path segments and uses Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the narrow shared-helper hardening after maintainer review and exact-head gates, since current main and the latest release still lack the guard. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main indexes raw dotted path segments and uses Is this the best way to solve the issue? Yes. Reusing AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 26f92a4f8d5f. Label changesLabel justifications:
Evidence reviewedPR surface: Source +15, Tests +19. Total +34 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
Real behavior proof (per
|
|
ClawSweeper PR egg ✨ Hatched: 💎 rare Mossy Branchling Hatch commandComment Hatchability rules:
Rarity: 💎 rare. What is this egg doing here?
|
|
This pull request has been automatically marked as stale due to inactivity. |
|
Added the requested direct runtime proof for the defaults fallback path in Behavior addressed: blocked prototype-key paths do not resolve through either inherited defaults or own defaults, while ordinary unresolved paths still use own defaults. Real environment tested: local OpenClaw source checkout on this PR branch with Node v22.22.1. Exact steps or command run after this patch: node --import tsx --input-type=module <<'NODE'
import { isConfigPathTruthyWithDefaults } from './src/shared/config-eval.ts';
// Exercise normal config, own defaults, inherited defaults, and blocked keys.
NODE
node scripts/test-projects.mjs src/shared/config-eval.test.tsEvidence after fix: {
"node": "v22.22.1",
"rows": [
{ "path": "feature.enabled", "why": "real config true", "result": true },
{ "path": "browser.enabled", "why": "real config false overrides default", "result": false },
{ "path": "browser.missing", "why": "own default true for unresolved normal path", "result": true },
{ "path": "browser.inherited", "why": "inherited default ignored", "result": false },
{ "path": "constructor", "why": "blocked path ignores inherited default", "result": false },
{ "path": "__proto__.enabled", "why": "blocked path ignores inherited default", "result": false },
{ "path": "prototype.enabled", "why": "blocked path ignores inherited default", "result": false },
{ "path": "constructor", "why": "blocked path ignores own default", "result": false },
{ "path": "__proto__.enabled", "why": "blocked path ignores own default", "result": false },
{ "path": "prototype.enabled", "why": "blocked path ignores own default", "result": false }
]
}Observed result after fix: Validation: What was not tested: no full gateway startup was run; this proof is scoped to the shared config-eval helper used by skill/hook eligibility. @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Summary
resolveConfigPathinsrc/shared/config-eval.tstraverses config objects by dot-separated path strings (e.g."foo.bar.baz"), but does not check whether any path segment is a dangerous prototype key (__proto__,prototype, orconstructor). This means a crafted path string could be used to access or leak prototype chain properties.Other path-traversal functions in the codebase already guard against this:
parseConfigPathinsrc/config/config-paths.tsmerge-patch.ts,runtime-overrides.ts,includes.ts, and othersAll of these use the shared
isBlockedObjectKeyutility fromsrc/infra/prototype-keys.ts.Changes
isBlockedObjectKeyfrom../infra/prototype-keys.jsresolveConfigPathloop that returnsundefinedwhen a blocked key is encounteredTest plan
resolveConfigPathandisConfigPathTruthyWithDefaultscontinue to pass__proto__,prototype, orconstructorsegments now returnundefinedReal behavior proof
resolveConfigPathnow blocks prototype-key path segments before object property access while preserving normal dot-path resolution.origin/main, branchcodex-refresh-59694, inspected with the realgitandrgCLIs against the patched repository.git diff -- src/shared/config-eval.ts src/shared/config-eval.test.ts rg -n "isBlockedObjectKey|blocks prototype keys" src/shared/config-eval.ts src/shared/config-eval.test.tssafe.enabledresolving while__proto__,constructor.name, andprototype.pollutedreturnundefined.node_modules; CI should run the complete project checks.