fix(exec): strip invalid approval policy enums during config normalization#59112
Conversation
Greptile SummaryThis PR fixes a real bug where invalid enum strings like
Confidence Score: 5/5Safe to merge; the bug fix is correct and well-tested, with only a minor false-positive in change detection that has no functional impact. The core fix is correct: invalid enum values are now stripped at normalization time, and the downstream resolution layer correctly falls through to built-in defaults. The one remaining finding (null !== undefined false-positive causing spurious agent object rebuilds) is P2 — it does not affect JSON serialization, property access semantics, or runtime behavior in any observable way. All P2 findings default to 5/5. No files require special attention for merge, though the agentChanged comparison in src/infra/exec-approvals.ts could be tightened to avoid spurious rebuilds of unchanged agent entries. Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/infra/exec-approvals.ts
Line: 308-312
Comment:
**False-positive change detection for agents with absent fields**
When an agent doesn't have `security`, `ask`, or `askFallback` set at all (i.e. `undefined`), `normalizeExecSecurity(undefined)` returns `null`, making the comparison `null !== undefined` evaluate to `true`. This marks every agent without explicit security/ask/askFallback as changed, causing a new object to be created for it with those keys explicitly present as `undefined`.
Example: an agent like `{ allowlist: [...] }` (no security fields) will have `agentChanged = true` solely because `null !== undefined`, and the rebuilt object will have `security: undefined, ask: undefined, askFallback: undefined` as explicit keys — different from the original (no keys at all).
While functionally harmless today (`JSON.stringify` drops `undefined` and property access returns `undefined` either way), this defeats the purpose of the change-detection guard and makes the returned `agents` object differ in shape from the input even for unmodified entries.
A straightforward fix is to convert `null` → `undefined` before comparing:
```suggestion
const agentChanged =
allowlist !== agent.allowlist ||
(validatedSecurity ?? undefined) !== agent.security ||
(validatedAsk ?? undefined) !== agent.ask ||
(validatedAskFallback ?? undefined) !== agent.askFallback;
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(exec): strip invalid security/ask en..." | Re-trigger Greptile |
🔒 Aisle Security AnalysisWe found 2 potential security issue(s) in this PR:
1. 🟠 Type confusion enables unintended activation of autoAllowSkills in exec approvals policy
Description
Impact:
Vulnerable code: function sanitizeExecApprovalPolicy(...): ExecApprovalsDefaults {
return {
...,
autoAllowSkills: policy?.autoAllowSkills,
};
}And later: autoAllowSkills: Boolean(defaults.autoAllowSkills ?? fallbackAutoAllowSkills),RecommendationValidate/coerce Suggested fix: function toBooleanOrUndefined(value: unknown): boolean | undefined {
return typeof value === "boolean" ? value : undefined;
}
function sanitizeExecApprovalPolicy(...): ExecApprovalsDefaults {
return {
security: normalizeExecSecurity(toStringOrUndefined(policy?.security)) ?? undefined,
ask: normalizeExecAsk(toStringOrUndefined(policy?.ask)) ?? undefined,
askFallback: normalizeExecSecurity(toStringOrUndefined(policy?.askFallback)) ?? undefined,
autoAllowSkills: toBooleanOrUndefined((policy as any)?.autoAllowSkills),
};
}
// When resolving, treat only explicit true as enabled
autoAllowSkills: (defaults.autoAllowSkills ?? fallbackAutoAllowSkills) === true,This ensures non-boolean values cannot silently enable the feature. 2. 🟠 Prototype Pollution via attacker-controlled agent keys in normalizeExecApprovals
Description
Vulnerable code: for (const [key, agent] of Object.entries(agents)) {
// ...
if (agentChanged) {
agents[key] = {
...agent,
allowlist,
security: sanitizedPolicy.security,
ask: sanitizedPolicy.ask,
askFallback: sanitizedPolicy.askFallback,
};
}
}RecommendationTreat
Example fix: const agents: Record<string, ExecApprovalsAgent> = Object.create(null);
for (const [key, agent] of Object.entries(file.agents ?? {})) {
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
agents[key] = agent;
}
// ... then iterate over Object.entries(agents) safelyAlternatively, store agents in a Analyzed PR: #59112 at commit Last updated on: 2026-04-02T08:32:34Z |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aed0c0aa1c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
aed0c0a to
1ca2d4a
Compare
1ca2d4a to
469794a
Compare
|
All bot feedback has been addressed in the latest commits:
(Note: The "DoS via null agent entry" finding from the security bot refers to a scenario where an agent value in the JSON is The CI failure on Ready for review. |
…ation (#59112) * fix(exec): strip invalid security/ask enum values during config normalization * fix(exec): narrow invalid approvals config cleanup --------- Co-authored-by: scoootscooob <[email protected]>
…ation (openclaw#59112) * fix(exec): strip invalid security/ask enum values during config normalization * fix(exec): narrow invalid approvals config cleanup --------- Co-authored-by: scoootscooob <[email protected]>
…ation (openclaw#59112) * fix(exec): strip invalid security/ask enum values during config normalization * fix(exec): narrow invalid approvals config cleanup --------- Co-authored-by: scoootscooob <[email protected]>
…ation (openclaw#59112) * fix(exec): strip invalid security/ask enum values during config normalization * fix(exec): narrow invalid approvals config cleanup --------- Co-authored-by: scoootscooob <[email protected]>
…ation (openclaw#59112) * fix(exec): strip invalid security/ask enum values during config normalization * fix(exec): narrow invalid approvals config cleanup --------- Co-authored-by: scoootscooob <[email protected]>
…ation (openclaw#59112) * fix(exec): strip invalid security/ask enum values during config normalization * fix(exec): narrow invalid approvals config cleanup --------- Co-authored-by: scoootscooob <[email protected]>
…ation (openclaw#59112) * fix(exec): strip invalid security/ask enum values during config normalization * fix(exec): narrow invalid approvals config cleanup --------- Co-authored-by: scoootscooob <[email protected]>
Summary
This PR fixes the malformed
exec-approvals.jsonpolicy-value path from #59006.When
~/.openclaw/exec-approvals.jsoncontains invalid enum values such asdefaults.security: "none",normalizeExecApprovals()was preserving those raw strings in memory. Downstream exec policy resolution assumes normalized values, so those invalid strings could leak into comparisons likeminSecurity()/maxAsk()and produce inconsistent behavior instead of cleanly falling back to the documented defaults.The fix is intentionally narrow:
security,ask, andaskFallbackwhile normalizing the fileundefinedWhat Changed
src/infra/exec-approvals.tssecurity,ask, andaskFallbacknormalizeExecApprovals()focused on structural cleanupsrc/infra/exec-approvals-config.test.tsScope Boundary
This PR does not change:
It only ensures that malformed policy values from
exec-approvals.jsondo not corrupt the in-memory exec approvals config.Reproduction
~/.openclaw/exec-approvals.json, for example:{ "version": 1, "defaults": { "security": "none" }, "agents": {} }Verification
pnpm test -- src/infra/exec-approvals-config.test.tspnpm buildpnpm checkChange Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Addresses the malformed
exec-approvals.jsonpolicy-value path in #59006.