-
-
Notifications
You must be signed in to change notification settings - Fork 69k
[Bug]: /elevated allowlist can be bypassed by matching recipient (ctx.To) instead of sender #11022
Description
CVSS Assessment
| Metric | Value |
|---|---|
| Score | 9.9 / 10.0 |
| Severity | Critical |
| Vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H |
Summary
/elevated authorization accepts ctx.To as an identity token, so recipient identifiers can satisfy sender allowlists. In WhatsApp inbound DM flows, To is set to the bot's own number for each message, allowing non-owner senders to pass tools.elevated.allowFrom.whatsapp checks when that allowlist contains the owner/self number.
This elevates the session to full when /elevated full is accepted, and embedded-agent exec calls then bypass approval prompts (ask=off).
Affected Code
File: source_code/src/auto-reply/reply/reply-elevated.ts:103
addToken(params.ctx.SenderName);
addToken(params.ctx.SenderUsername);
addToken(params.ctx.SenderTag);
addToken(params.ctx.SenderE164);
addToken(params.ctx.From);
addToken(stripSenderPrefix(params.ctx.From));
addToken(params.ctx.To);
addToken(stripSenderPrefix(params.ctx.To));File: source_code/src/web/inbound/monitor.ts:303
const inboundMessage: WebInboundMessage = {
id,
from,
conversationId: from,
to: selfE164 ?? "me",
// ...
};File: source_code/src/web/auto-reply/monitor/process-message.ts:279
const ctxPayload = finalizeInboundContext({
// ...
From: params.msg.from,
To: params.msg.to,
// ...
});File: source_code/src/auto-reply/reply/get-reply-run.ts:395
bashElevated: {
enabled: elevatedEnabled,
allowed: elevatedAllowed,
defaultLevel: resolvedElevatedLevel ?? "off",
},File: source_code/src/agents/pi-embedded-runner/run/attempt.ts:210
createOpenClawCodingTools({
exec: {
...params.execOverrides,
elevated: params.bashElevated,
},
// ...
});File: source_code/src/agents/bash-tools.exec.ts:946
const bypassApprovals = elevatedRequested && elevatedMode === "full";
if (bypassApprovals) {
ask = "off";
}Attack Surface
How is this reached?
- Network (HTTP/WebSocket endpoint, API call)
- Adjacent Network (same LAN, requires network proximity)
- Local (local file, CLI argument, environment variable)
- Physical (requires physical access to machine)
Authentication required?
- None (unauthenticated/public access)
- Low (any sender already authorized to issue commands, e.g. allowlisted/paired DM sender)
- High (admin/privileged user only)
Entry point: Inbound channel message with /elevated on|ask|full directive (for example WhatsApp DM).
Exploit Conditions
Complexity:
- Low (no race/timing required once configuration and sender access are present)
- High (requires race condition, specific config, or timing)
User interaction:
- None (automatic, no victim action needed)
- Required (victim must click, visit, or perform action)
Prerequisites:
tools.elevated.enabled=truetools.elevated.allowFrom.whatsappincludes the owner/self E.164- Attacker is already allowed to send command-capable inbound messages (for example paired/allowlisted sender)
Impact Assessment
Scope:
- Unchanged (impact limited to vulnerable component)
- Changed (can affect other components, escape sandbox)
What can an attacker do?
| Impact Type | Level | Description |
|---|---|---|
| Confidentiality | High | Read arbitrary host data by running privileged exec flows after /elevated full. |
| Integrity | High | Execute host commands that modify files/config/state outside intended per-sender controls. |
| Availability | High | Disrupt service by running destructive or terminating commands without approval prompts. |
Steps to Reproduce
- Configure WhatsApp inbound with at least two command-capable senders (owner + another sender), and set
tools.elevated.allowFrom.whatsappto the owner/self E.164. - From the non-owner sender, send
/elevated full. - Observe the directive is accepted (
Elevated mode set to full (auto-approve).). - Send a normal message that causes the embedded agent to invoke
exec(for example, ask it to runidor list files on host). - Observe host exec runs without approval prompts because exec defaults now resolve to elevated
full(ask=off).
Notes
!id / !ls go through the /bash command path, which currently creates a separate exec tool with defaultLevel: "on" (ask-level), so that specific command form is not the approval-bypass path for this bug.
Recommended Fix
Use only sender-authenticated identities for elevated authorization. Remove ctx.To (and its stripped variant) from the token set. Prefer stable sender IDs (SenderId, provider-native immutable IDs, E.164 where applicable) over mutable display names. Treat recipient/conversation fields as routing metadata, never authorization principals.
References
- CWE: CWE-285 - Improper Authorization