GHSA-7j5w-7r7x-9v27: Critical severity npm/codewhale vulnerability

Published Sep 4, 2026
·
Updated

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 9a34b5034d29f05d1f28fa61b04719ca6a741020. Users should upgrade to 0.8.64 or later. The original reporter analysis is preserved below.

Argument Injection in gitshow Tool Allows Arbitrary File Write Without Approval

Overview

The gitshow tool in DeepSeek-TUI executes git show with the model-supplied rev parameter passed unvalidated into the argv. git show honours the --output=<path> option, so a rev value beginning with --output= is interpreted as a flag rather than a revision. The tool is registered with ApprovalRequirement::Auto and declares ToolCapability::ReadOnly, so the write happens without a user prompt and contradicts the capability the catalog advertises to the model and the user.

This is the same vulnerability class as GHSA-72w5-pf8h-xfp4 (CVE-2026-45374): an auto-approved tool produces an effect outside the boundary the user consented to.

Impact

A malicious repository combined with prompt injection, the threat model already documented in CVE-2026-45311 (auto-loaded AGENTS.md is treated as instructions by the model) yields an unprompted arbitrary file write at the privilege of the user running DeepSeek-TUI.

Useful targets reachable as the invoking user:

- ~/.ssh/authorizedkeys - ~/.bashrc, ~/.zshrc, ~/.profile - ~/.gitconfig (chainable into RCE via core.editor) - ~/.config/, ~/.aws/credentials, project source files

The written content is the git show rendering of HEAD commit hash, author/date header, indented commit message, and (when patch=true) diff hunks. The commit subject, body, author identity, and diff text are entirely attacker-controlled because the attacker owns the repository HEAD. The leading commit <hash> line prevents clean overwrite of formats that reject unknown tokens, but is silently ignorable in files parsed as comments-or-text (crontab, dotfiles consumed by tolerant readers) and is irrelevant for the destructive/DoS sub-case (clobbering ~/.ssh/authorizedkeys locks the user out; clobbering a project file corrupts source).

Technical Details

Root Cause

crates/tui/src/tools/githistory.rs:

rust // L196-198 fn approvalrequirement(&self) -> ApprovalRequirement { ApprovalRequirement::Auto }

// L204-228 (excerpt) async fn execute(&self, input: Value, context: &ToolContext) -> Result<ToolResult, ToolError> { let rev = requiredstr(&input, "rev")?; ... let mut args = vec![ "show".tostring(), "--no-color".tostring(), "--no-ext-diff".tostring(), ]; if patch { args.push(format!("--unified={unified}")); } else { args.push("--no-patch".tostring()); } if stat { args.push("--stat".tostring()); } args.push(rev.tostring()); // unvalidated, no --end-of-options sentinel ... }

The JSON schema for rev is {"type": "string"} (L161-164) with no pattern, no enum, and no length cap. requiredstr performs no semantic validation. The argv has no --end-of-options separator between the trailing options and rev, so git's option parser keeps consuming flags from rev.

The same pattern in gitblame (L322-388) is tracked in a separate advisory.

Why --output Works

git show shares its option parser with git log / git diff, which expose --output=<file>. The implementation opens the path with OWRONLY | OCREAT | OTRUNC and writes the formatted output there. No permission check beyond the filesystem's own running as the user is sufficient to clobber anything the user owns.

Proof of Concept

The vulnerable argv assembled by the tool when invoked with {"rev": "--output=/home/victim/.bashrc"} is equivalent to:

git show --no-color --no-ext-diff --no-patch --stat --output=/home/victim/.bashrc

Reproduced against system git as a non-root user:

$ id uid=1001(lowtest) gid=1001(lowtest) groups=1001(lowtest)

$ cd /tmp/lp && git init -q $ echo a > a.txt && git add a.txt $ git -c user.email=a@b -c user.name=a commit -q -m "lol"

$ git show --no-color --no-patch "--output=/home/lowtest/.bashrcclobbered" HEAD $ ls -la /home/lowtest/.bashrcclobbered -rw-rw-r-- 1 lowtest lowtest 128 May 19 07:05 /home/lowtest/.bashrcclobbered

End-to-end exploitation path:

- Attacker publishes a repository whose AGENTS.md instructs the model to call gitshow with rev set to a crafted --output= string targeting a file in the victim's home directory. The same auto-load pathway documented in CVE-2026-45311 applies. - Victim opens the repository in DeepSeek-TUI and issues any prompt that exercises the agent loop. - The model issues the tool call. Because approvalrequirement() returns Auto, no approval UI is shown. - git show --output=<path> overwrites the target file with attacker-controlled commit metadata and diff text.

Remediation

Two changes in crates/tui/src/tools/githistory.rs:

Insert an end-of-options sentinel before rev so git stops parsing flags:

rust args.push("--end-of-options".tostring()); args.push(rev.tostring());

Reject rev values that begin with - (or restrict to a revision-shape regex ^[A-Za-z0-9./^~@:{}-]+$ after the leading character check):

rust if rev.startswith('-') { return Err(ToolError::invalidinput("rev must not start with '-'")); }

A regression test mirroring runtestsrequiresuserapproval (testrunner.rs:197) should assert that rev = "--output=/tmp/x" is rejected.

Affected Software

4 affected componentsFixes available
npm/codewhale>=0.8.41<0.8.64
0.8.64
rust/codewhale-tui>=0.8.41<0.8.64
0.8.64
npm/deepseek-tui>=0.3.27<0.8.41
0.8.41
rust/deepseek-tui>=0.3.27<=0.8.41

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/codewhale to a version that resolves this vulnerability.

    Fixed in 0.8.64
  2. Upgrade

    Upgrade rust/codewhale-tui to a version that resolves this vulnerability.

    Fixed in 0.8.64
  3. Upgrade

    Upgrade npm/deepseek-tui to a version that resolves this vulnerability.

    Fixed in 0.8.41
  4. Upgrade

    Upgrade DeepSeek-TUI (crates/tui/src/tools/git_history.rs) to a version that resolves this vulnerability.

    Fixed in 0.8.64Patch 9a34b5034d29f05d1f28fa61b04719ca6a741020
  5. Configuration

    Implement validation in the git_show tool so that the `rev` input passed to `git show` is rejected when it starts with `-` (the material notes a check `if rev.starts_with('-')` returning `ToolError::invalid_input("rev must not start with '-'")`), preventing crafted `--output=...` from being interpreted as an option.

    git show invocation in git_history.rs (git_show tool) rev validation = reject rev strings that begin with '-'
  6. Configuration

    Ensure the `git show` argv places `--end-of-options` before the user-supplied `rev` value, so option parsing does not treat attacker-controlled `--output=<path>` as flags.

    git show invocation in git_history.rs (git_show tool) end-of-options handling = prepend `--end-of-options` before the user-supplied rev argument

Event History

Sep 4, 2026
Advisory Published
via GitHub·06:02 PM
Data Sourced
via GitHub·06:02 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who is realistically exposed to this issue?

Users of the affected CodeWhale or DeepSeek-TUI packages are exposed when a malicious repository and prompt injection can cause the model to supply a crafted revision value to the git_show tool. The issue is particularly significant because the tool is auto-approved.

2

Does exploitation require user approval or elevated privileges?

No user approval is required for the git_show action because it is registered with ApprovalRequirement::Auto. An attacker needs to influence the model-supplied rev parameter so that it begins with --output=<path>.

3

What can an attacker do through the vulnerable parameter?

A crafted rev value can be interpreted by git show as its --output option rather than as a revision. This allows an arbitrary file write even though the tool is declared as read-only.

4

How can I remediate this issue?

Upgrade to version 0.8.64 or later, which contains the fix in commit 9a34b5034d29f05d1f28fa61b04719ca6a741020. Package ranges affected by the advisory are recorded in its metadata.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203