Skip to content

security: harden default tool policies and secure shell execution#16320

Closed
SuccessSoham wants to merge 8 commits intoopenclaw:mainfrom
SuccessSoham:security/harden-default-policies
Closed

security: harden default tool policies and secure shell execution#16320
SuccessSoham wants to merge 8 commits intoopenclaw:mainfrom
SuccessSoham:security/harden-default-policies

Conversation

@SuccessSoham
Copy link
Copy Markdown

@SuccessSoham SuccessSoham commented Feb 14, 2026

Security Improvements

This PR implements several security hardenings identified during a recent audit.

1. Default Tool Policy Hardening (Critical)

  • Problem: The system previously defaulted to "allow-all" tools if no specific policy was configured for a group or sender. This potentially exposed dangerous tools (like exec) to untrusted users in default configurations.
  • Fix: Changed isToolAllowedByPolicyName in src/agents/pi-tools.policy.ts to default to false (deny-all).
  • Context: Added senderIsOwner parameter to policy checks. Only verified owners bypass the policy check when no policy is present. All other users are denied by default if no explicit policy allows access.

2. Privilege Escalation Fix (High)

  • Problem: Unauthorized /exec directives (e.g. host=gateway) persisted in the session context even when the sender was not authorized to run commands.
  • Fix: Updated src/auto-reply/reply/get-reply-directives.ts to explicitly clear hasExecDirective and related fields when commandAuthorized is false.

3. Secure Windows Shell Execution (High)

  • Problem: runCommandWithTimeout used shell: true implicitly for non-exe files on Windows, which is vulnerable to command injection via shell metacharacters in arguments.
  • Fix: Refactored src/process/exec.ts to explicitly detect batch files (.cmd, .bat) and execute them using cmd.exe /c with windowsVerbatimArguments: true. All other executions now use shell: false.

4. Audit Enhancements (Medium)

  • Problem: trusted-proxy auth mode is insecure if trustedProxies is empty, allowing header spoofing.
  • Fix: Added a critical check in src/security/audit.ts to flag empty trustedProxies configuration when trusted-proxy mode is enabled.

Verification

  • pnpm build passes.
  • Existing tests should pass (no logic changes for configured policies).
  • Manual verification of Windows execution and directive parsing logic.

Thanks to @SuccessSoham for the contribution.

Greptile Summary

This PR hardens security defaults across tool policies, exec directive handling, Windows shell execution, and audit messaging. The most impactful change is the deny-by-default policy in isToolAllowedByPolicyName when no explicit policy is configured, with an senderIsOwner bypass for verified owners. All call sites have been updated to propagate the new parameter.

  • Default tool policy (pi-tools.policy.ts): Changed from allow-all to deny-all when no policy exists; only verified owners bypass. The senderIsOwner parameter is correctly threaded through filterToolsByPolicy, isToolAllowedByPolicies, and applyToolPolicyPipeline.
  • Exec directive clearing (get-reply-directives.ts): Unauthorized senders now have exec directive fields cleared to prevent privilege escalation of /exec directives persisting in session context.
  • Windows shell hardening (exec.ts): Replaces implicit shell: true with explicit cmd.exe /c for .cmd/.bat files and shell: false everywhere else. Caller-supplied windowsVerbatimArguments is honored via || fallback.
  • Audit message (audit.ts): The updated detail text for empty trustedProxies is factually incorrect — the gateway rejects all requests in this case (see src/gateway/auth.ts:318-319), it does not allow identity spoofing. This should be corrected before merge.
  • Audit extras (audit-extra.async.ts, audit-extra.sync.ts): Pass senderIsOwner: true to preserve worst-case exposure modeling in audit checks.

Confidence Score: 3/5

  • Generally safe security hardening, but contains one factually incorrect audit message that could mislead operators.
  • The core policy changes (deny-by-default, senderIsOwner threading) are sound and all call sites are updated. The exec directive clearing and Windows shell hardening are correct. However, the audit.ts change introduces an incorrect description: it claims empty trustedProxies allows identity spoofing, when the actual code rejects all requests. This misinformation in a security audit tool could lead to wrong operational decisions.
  • src/security/audit.ts — the updated finding detail text is factually incorrect and contradicts the actual runtime behavior in src/gateway/auth.ts

Last reviewed commit: fba4dee

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: M labels Feb 14, 2026
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 14, 2026

Additional Comments (1)

src/process/exec.ts
Unused destructured variable

windowsVerbatimArguments is destructured from options here but never used — the spawn call on line 130 uses isCmdBatch instead. This should either be removed (if the option is intentionally deprecated) or used in the spawn call (see comment on line 130).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/process/exec.ts
Line: 88:88

Comment:
**Unused destructured variable**

`windowsVerbatimArguments` is destructured from `options` here but never used — the spawn call on line 130 uses `isCmdBatch` instead. This should either be removed (if the option is intentionally deprecated) or used in the spawn call (see comment on line 130).

How can I resolve this? If you propose a fix, please make it concise.

@SuccessSoham
Copy link
Copy Markdown
Author

This Pull Request addresses the security vulnerabilities documented in issue #16323.

@SuccessSoham SuccessSoham force-pushed the security/harden-default-policies branch from aa018b6 to 8a32ebb Compare February 14, 2026 16:56
@SuccessSoham
Copy link
Copy Markdown
Author

I have updated the PR to address the suggestions from @greptile-apps:

  • Fixed windowsVerbatimArguments propagation in exec.ts to ensure URLs and quoted commands continue to work correctly on Windows.
  • Updated security audits to pass senderIsOwner: true for exposure-matrix checks, ensuring they reflect "worst-case" potential exposure.
  • Propagated senderIsOwner in the gateway HTTP tool invocation path for consistency.

@openclaw-barnacle openclaw-barnacle bot added gateway Gateway runtime size: S and removed size: M labels Feb 14, 2026
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

8 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

…anks Soham)

Implementation details:
- Enforce 'Deny-All' default tool policy for untrusted users in pi-tools.policy.ts.
- Propagate 'senderIsOwner' context through tool filtering in pi-tools.ts.
- Explicitly clear unauthorized /exec directives in get-reply-directives.ts to prevent privilege escalation.
- Secure Windows shell execution in process/exec.ts by explicitly using 'cmd.exe /c' for batch files and disabling implicit shell.
- Enhance security audit in audit.ts to flag critical trusted-proxy misconfigurations.
@SuccessSoham SuccessSoham force-pushed the security/harden-default-policies branch from 8a32ebb to 1a54e1e Compare February 14, 2026 17:09
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

9 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +402 to +403
"This allows anyone who can reach the gateway port to spoof user identity.",
remediation: "Set gateway.trustedProxies to the specific IP(s) of your reverse proxy.",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Audit detail contradicts actual runtime behavior

The new message claims empty trustedProxies "allows anyone who can reach the gateway port to spoof user identity," but authorizeGatewayConnect in src/gateway/auth.ts:318-319 explicitly returns { ok: false, reason: "trusted_proxy_no_proxies_configured" } when the list is empty — meaning all requests are rejected, not spoofable.

The original wording ("All requests will be rejected.") was accurate. This change introduces a misleading audit finding that could cause operators to misdiagnose the actual problem (a denial-of-service to themselves, not an identity spoofing vulnerability).

Suggested change
"This allows anyone who can reach the gateway port to spoof user identity.",
remediation: "Set gateway.trustedProxies to the specific IP(s) of your reverse proxy.",
"This configuration rejects all incoming requests since no proxy is trusted. " +
"Set gateway.trustedProxies to allow traffic from your reverse proxy.",
remediation: "Set gateway.trustedProxies to the specific IP(s) of your reverse proxy.",
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/security/audit.ts
Line: 402:403

Comment:
**Audit detail contradicts actual runtime behavior**

The new message claims empty `trustedProxies` "allows anyone who can reach the gateway port to spoof user identity," but `authorizeGatewayConnect` in `src/gateway/auth.ts:318-319` explicitly returns `{ ok: false, reason: "trusted_proxy_no_proxies_configured" }` when the list is empty — meaning all requests are **rejected**, not spoofable.

The original wording ("All requests will be rejected.") was accurate. This change introduces a misleading audit finding that could cause operators to misdiagnose the actual problem (a denial-of-service to themselves, not an identity spoofing vulnerability).

```suggestion
          "This configuration rejects all incoming requests since no proxy is trusted. " +
          "Set gateway.trustedProxies to allow traffic from your reverse proxy.",
        remediation: "Set gateway.trustedProxies to the specific IP(s) of your reverse proxy.",
```

How can I resolve this? If you propose a fix, please make it concise.

@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added stale Marked as stale due to inactivity and removed stale Marked as stale due to inactivity labels Feb 22, 2026
@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Mar 13, 2026
@openclaw-barnacle
Copy link
Copy Markdown

Closing due to inactivity.
If you believe this PR should be revived, post in #pr-thunderdome-dangerzone on Discord to talk to a maintainer.
That channel is the escape hatch for high-quality PRs that get auto-closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling gateway Gateway runtime size: S stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants