[FEATURE] AskUserBash tool — let agents prompt for secrets without exposing them to the model

Resolved 💬 3 comments Opened Apr 29, 2026 by 0xnfrith Closed May 31, 2026

Preflight Checklist

  • [x] I have searched existing requests — see Related issues below.
  • [x] This is a single feature request.

Related issues

  • #29910Built-in secrets management with optional third-party integrations (open). This proposal is meaningfully smaller in scope: a single tool primitive Claude can call, not a full vault subsystem. It is a viable first step that unblocks the same security goal ("secrets should never appear in chat context") without committing to the larger architecture, and could serve as the underlying input primitive for #29910.
  • #38797Secure/masked input for sensitive data entry (closed as duplicate of #29910). This proposal differs by being a tool Claude calls during its agentic flow (not a slash command the user invokes) and by piping the value directly into a local bash command rather than storing it.

Problem statement

Today, when a user wants Claude Code to do anything that needs a secret — a GitHub PAT for gh auth login, an OPENAI_API_KEY for .env.local, an MFA code, a private SSH key — the only path inside the agentic loop is to paste the secret into chat. The moment that happens:

  • The value enters the model's context window.
  • It's transmitted to the API.
  • It's persisted in ~/.claude/projects/*.jsonl transcripts.
  • It's potentially captured in screen recordings, terminal scrollback, and IDE clipboards.

The user's only alternative is to leave Claude Code, handle the secret in a separate terminal, and come back — defeating the point of an agentic CLI.

Proposed solution

A new built-in tool, alongside AskUserQuestion:

AskUserBash({
  label: string,    // displayed above the input field
  preview: string,  // human-readable description of what the bash command will do
  bashCmd: string,  // template; user input is substituted for $ARG1
})

When Claude calls this tool, Claude Code renders an inline secure-input form. The user types or pastes their value. On submit:

  1. The input is substituted for $ARG1 (and only $ARG1) in bashCmd.
  2. The resolved command is executed locally via the user's shell.
  3. Only an exit-code-equivalent boolean is returned to the model — never the input, never the resolved command, never stdout/stderr.

The model sees { ok: true } or { ok: false } and proceeds.

Demos

Two screenshots, both showing the same tool rendered with different (label, preview, bashCmd) payloads.

Demo 1 — GitHub PAT into gh auth login:

AskUserBash({ label: "GitHub Personal Access Token", preview: "Pipe token into gh CLI — never sent to the model", bashCmd: "echo $ARG1 | gh auth login --with-token" })

<!-- drag screenshot 1 here: ~/Desktop/askuserbash-feature-request.png -->

<img width="2000" height="1125" alt="Image" src="https://github.com/user-attachments/assets/8ef25e56-12dc-4c69-a56b-9ef6397aaf0d" />

Demo 2 — OpenAI key into .env.local:

AskUserBash({ label: "OPENAI_API_KEY", preview: "Append to .env.local without touching the model context", bashCmd: "printf 'OPENAI_API_KEY=%s\n' \"$ARG1\" >> .env.local" })

<!-- drag screenshot 2 here: ~/Desktop/askuserbash-feature-request-2.png -->

<img width="2000" height="1125" alt="Image" src="https://github.com/user-attachments/assets/ef3235ad-c963-45ea-b4b3-16ce2d5443f5" />

Security model

| Channel | Visible to model? |
|---|---|
| label, preview, bashCmd template | Yes — the model authored these |
| User input (the value typed into the form) | No |
| Resolved command (after $ARG1 substitution) | No |
| stdout / stderr | No |
| Exit-code-equivalent boolean | Yes |

The user sees the bashCmd template before typing — they always know exactly what will run with their input. This preserves Claude Code's existing trust model (user inspects → user approves → Claude runs) while closing the secret-shaped hole.

Use cases this unblocks

  • echo $ARG1 | gh auth login --with-token
  • printf 'OPENAI_API_KEY=%s\n' "$ARG1" >> .env.local
  • echo "$ARG1" | wrangler secret put STRIPE_WEBHOOK_SECRET
  • op item edit "Anthropic API" credential="$ARG1"
  • aws-vault exec prod --mfa-token=$ARG1 -- aws s3 ls
  • printf '%s' "$ARG1" | ssh-add -
  • kubectl create secret generic api --from-literal=token=$ARG1
  • Anything else a user would otherwise paste into chat and immediately regret.

Why a tool primitive, not a full secrets manager

AskUserBash is composable with whatever secrets infrastructure the user already has — 1Password, Doppler, AWS Secrets Manager, plain .env, Cloudflare bindings, system keychain. It's the input edge: the missing primitive that lets Claude help with secret-handling workflows without ever seeing the secret.

  • Users with no secrets infra can use it to write to .env.local.
  • Users with sophisticated infra can pipe into op item edit, wrangler secret put, vault kv put, etc.

This makes AskUserBash implementable as a small, well-scoped feature on top of the existing tool / form infrastructure, while moving the security needle today. It does not preclude #29910's larger proposal — it could be the underlying primitive that powers it.

Alternative API shapes considered

  • AskUserSecureInput(label) → value — returns the raw value to the model. Defeats the purpose; the secret still enters context.
  • A /secret slash command — user-driven only; doesn't fit Claude's agentic flow where Claude recognizes that a secret is needed and asks for it. Tool form is the right shape.
  • bashCmd with arbitrary $ARG1..N — multi-input would be a small extension; single input keeps v1 surface minimal.
  • Returning stdout to the model — tempting, but a single error message can leak the secret. Keep the return channel boolean-only; let the model retry with { ok: false }.

Priority

High — this is the single highest-leverage tactical security feature for users today, and it's small enough to ship as an MVP.

Feature category

Tools / Interactive mode (TUI) / Security

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗