CVE-2026-75858: CodeWhale: rlm_eval auto-approves arbitrary Python execution, bypassing the user's approval policy (RCE)
CodeWhale's `rlm_eval` tool runs model-chosen Python in a real `python3` interpreter and marks itself as never needing approval, so the user's `--approval-policy` is ignored. Prompt injection from content the agent reads can run code on the developer's machine with no prompt. Fixed in 0.8.64.
Published Sep 4, 2026 · Analysis Oct 24, 2026
What an attacker can do
rlm_eval in crates/tui/src/tools/rlm.rs takes a code string from the model and runs it. Its approval_requirement() returns ApprovalRequirement::Auto, which overrides the trait default that would require approval for tools with the ExecutesCode capability. The engine's check, spec.approval_requirement() != ApprovalRequirement::Auto && !registry.context().auto_approve, is then false, so no approval event is raised under on-request, unless-trusted or never. The companion tool rlm_open has the same Auto setting. It can stage content, a file or a URL fetch for the kernel. Both tools are registered by default and cannot be disabled.
An attacker needs the agent to read content they control: a web page, a fetched URL, a repo file or an MCP tool result. A prompt injection there can make the model call rlm_open and rlm_eval. The code runs with no sandbox at the user's UID. It can read SSH keys, cloud credentials and ~/.codewhale/auth.json, write to shell rc files or authorized_keys, and reach the network. The same defect was patched earlier on the run_tests tool (CVE-2026-45311). That fix did not reach these tools.
Who is affected
The package names changed along the way. The advisory lists:
codewhale(npm) andcodewhale-tui(Rust): 0.8.41 up to but not including 0.8.64.deepseek-tui(npm): 0.8.33 up to but not including 0.8.41.deepseek-tui(Rust crate): 0.8.33 through 0.8.41, with no patched version listed.
npm ls -g codewhale deepseek-tui
codewhale --versionEvery default install is affected, since the tools are registered unconditionally.
deepseek-tui
- Ecosystem
- Rust (crates.io)
- Affected
- >= 0.8.33, <= 0.8.41
- Fixed in
- No patched version yet
- Check
cargo tree -i deepseek-tui
deepseek-tui
- Ecosystem
- npm
- Affected
- >= 0.8.33, < 0.8.41
- Fixed in
- 0.8.41
- Check
npm ls deepseek-tui
codewhale-tui
- Ecosystem
- Rust (crates.io)
- Affected
- >= 0.8.41, < 0.8.64
- Fixed in
- 0.8.64
- Check
cargo tree -i codewhale-tui
codewhale
- Ecosystem
- npm
- Affected
- >= 0.8.41, < 0.8.64
- Fixed in
- 0.8.64
- Check
npm ls codewhale
How to fix it
Upgrade to codewhale or codewhale-tui 0.8.64 or later. The fix is commit 57f3c89.
npm install -g codewhale@latestFor the old deepseek-tui npm package, the patched version listed is 0.8.41. The advisory lists no patched version for the deepseek-tui Rust crate, so move to codewhale-tui 0.8.64. The sources give no workaround. Avoid running the agent over untrusted content until you upgrade.
How to tell if you were hit
Look for a Python process started by the agent that you did not ask for, and for new files the agent should not write, such as /tmp/pwned_by_rlm_eval from the proof of concept. Check ~/.ssh/authorized_keys and shell rc files for recent edits, and the agent's session log for rlm_open or rlm_eval calls that happened without an approval dialog.
Beam records agent shell commands, file access and MCP tool calls, and its rules can flag risky ones, which helps with reviewing what the agent ran.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Maintainer resolution
The CodeWhale maintainers validated this report. The affected package ranges are recorded in the advisory metadata. Version 0.8.64 contains the fix in commit 57f3c89471e27ac4032d9791f6885e5d4408c381. Users should upgrade to 0.8.64 or later. The original reporter analysis is preserved below.
Summary
The rlm_eval tool runs an arbitrary Python string chosen by the model in a real python3 interpreter. Its approval_requirement() returns ApprovalRequirement::Auto, which the engine treats as "never prompt," regardless of the user's configured --approval-policy. A single tool call — which prompt injection from any untrusted content the agent reads (a web page, a fetched URL, a repo file, an MCP tool result) can induce — runs code on the user's machine at the user's privilege with no prompt and no audit step. This is the same defect that was already patched on the sibling run_tests tool (CVE-2026-45311); the fix never reached rlm_eval or rlm_open, which expose a broader surface (full Python on the host, not just cargo test).
Details
rlm_eval's execute() reads the LLM-controlled code field and runs it (crates/tui/src/tools/rlm.rs:215-300):
fn capabilities(&self) -> Vec<ToolCapability> {
vec![ToolCapability::Network, ToolCapability::ExecutesCode]
}
fn approval_requirement(&self) -> ApprovalRequirement {
ApprovalRequirement::Auto // overrides the safe default below
}
async fn execute(&self, input: Value, context: &ToolContext) -> Result<ToolResult, ToolError> {
let name = required_non_empty_str(&input, "name")?;
let code = required_non_empty_str(&input, "code")?; // LLM-controlled
...
let round = kernel.run(code, Some(&bridge)).await... // runs that code in python3The trait default at crates/tui/src/tools/spec.rs:632-633 would have returned Required for any tool whose capabilities include ExecutesCode. rlm_eval deliberately overrides that to Auto.
The engine's approval gate (crates/tui/src/core/engine.rs:845) is two AND-ed conditions, and a per-tool Auto makes the first one false:
let approval_required = spec.approval_requirement() != ApprovalRequirement::Auto
&& !registry.context().auto_approve;When approval_requirement() is Auto, approval_required is false, no Event::ApprovalRequired is emitted, and the user's --approval-policy (on-request, unless-trusted, never) is never consulted. The companion tool rlm_open (rlm.rs:142-143, same Auto, capabilities include ExecutesCode + Network) spawns the same Python kernel via PythonRuntime::spawn_with_context (rlm.rs:181) and can stage a content string, a file_path read, or a url fetch into the kernel before rlm_eval runs against it. Both tools are registered unconditionally by the default registry (crates/tui/src/tools/registry.rs:802-803); there is no flag to disable them.
PoC
Source-level reproduction. Point a provider's base_url at a local mock that returns canned tool_calls, then have the agent call rlm_open followed by rlm_eval with a code payload such as:
import os, getpass, socket
open('/tmp/pwned_by_rlm_eval','w').write(getpass.getuser()+'@'+socket.gethostname()+':'+os.getcwd())Run it through the non-interactive path (codewhale exec --auto) to confirm the tool executes, and through the plain interactive TUI under --approval-policy on-request (no --auto, no --yolo) to confirm no approval dialog appears. The sentinel file is written either way; the interactive run is the one that proves the policy is bypassed rather than waived.
Impact
Unsandboxed code execution on the user's workstation at the user's UID: read SSH keys, cloud credentials, ~/.codewhale/auth.json, and other secrets; write to shell rc files or authorized_keys for persistence; spawn subprocesses; reach the network. No filesystem, network, or process sandbox is applied to the spawned interpreter. Reachable with user interaction (running the agent over attacker-influenced content), no further prompt.
Credit
Credited to sai-sh.
Questions
- Does my approval policy protect me?
Not before 0.8.64.
rlm_evalreturnsAuto, so the engine never consults--approval-policy, includingon-requestandnever.- How is this triggered?
The model has to call the tool. Prompt injection in a web page, a fetched URL, a repository file or an MCP tool result can induce the call. The CVSS vector marks user interaction as required, since the user runs the agent over that content.
- Is this related to the `run_tests` bug?
Yes. The advisory says it is the same defect as CVE-2026-45311 on
run_tests. That fix never reachedrlm_evalorrlm_open.- Which version fixes CVE-2026-75858?
0.8.64 for
codewhaleandcodewhale-tui. The olddeepseek-tuinpm package is listed as fixed in 0.8.41.
References
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology
More Other MCP servers and tools vulnerabilities
All Other MCP servers and tools entriesCVE-2026-77361
obsidian-tc : Symlink read-ACL scope bypass via lexical path checks
medium4.7Oct 23, 2026CVE-2026-114126
Storybook dev server vulnerable to code injection from the local network
high8.7Oct 22, 2026CVE-2026-113731
djust: Arbitrary absolute-path file read in the find_handlers_for_template MCP tool
low3.3Oct 21, 2026CVE-2026-114125
Storybook: Missing origin validation in Storybook preview allows code injection from malicious websites
critical9.4Oct 21, 2026CVE-2026-111770
MCP TypeScript server SDK: Shared transport or server instances delivered one HTTP client's messages to another
high7.7Oct 20, 2026GHSA-953h-535j-jg2v
agent-router: MCP session resume does not verify the embedded anti-hijacking subject; default Helm seed makes session IDs forgeable
medium6.8Oct 19, 2026
