Skip to content

Keep password manager session tokens off the command line - #1959

Open
jeremy wants to merge 2 commits into
mainfrom
secrets-adapters-no-argv-sessions
Open

jeremy wants to merge 2 commits into
mainfrom
secrets-adapters-no-argv-sessions

Conversation

@jeremy

@jeremy jeremy commented Oct 6, 2026

Copy link
Copy Markdown
Member

The 1Password and Bitwarden secrets adapters pass a CLI session token to each command they run. Both put it somewhere it can end up in a process's command line:

  • 1Password: when op account get fails and the adapter falls back to op signin --raw, the token is passed to every op item get as --session <token>.
  • Bitwarden: commands are built as BW_SESSION=<token> bw ... and run with backticks. Ruby applies the leading assignment itself only when the string has no shell metacharacters; an escaped item name (one with a space, say) makes it run sh -c "<whole string>" instead.

This passes the token through the environment and runs the CLI with an argv array, no shell:

  • Adds Base#capture_command(*argv, env:), a thin IO.popen(env, argv, &:read) that sets $? like backticks, so the adapters' existing $?.success? checks and error messages are unchanged.
  • 1Password: signs in with op signin --account … --force (without --raw) and reads the OP_SESSION_<id> variable it prints for eval, then runs op item get with that variable in its environment. Desktop app integration and service account setups don't sign in this way and are unaffected.
  • Bitwarden: run_command takes its arguments as an array and sets BW_SESSION in the environment.

Values (item, vault, field names) now reach the CLI literally rather than through shell quoting.

The other adapters don't pass credentials on the command line (AWS, GCP, Doppler, Bitwarden Secrets Manager and Passbolt rely on the CLI's own stored login or env token; LastPass and Enpass pass none), so they're left as they are.

Tests

  • Adapter tests stub capture_command with exact argv and env (new stub_command helper), so a token in argv, or a command routed back through backticks, fails the stub.
  • test/secrets/base_adapter_test.rb runs a real process to check env is passed, arguments aren't shell-interpreted, and $? is set.

jeremy added 2 commits October 5, 2026 22:36
When `op account get` fails and the adapter falls back to `op signin`,
the resulting session token was passed to each `op item get` as
`--session <token>`, so it appeared in the process's command line (and
in a `sh -c` command line whenever the backtick string needed a shell).

Sign in without `--raw` and read the `OP_SESSION_<id>` variable `op`
prints for `eval`, then run `op item get` with that variable in its
environment, as an argv array with no shell. Item, vault and field
values are now passed to `op` literally rather than through shell
quoting.

Adds Base#capture_command, which runs an argv array via IO.popen with
an env hash and sets $? like backticks, so existing error handling is
unchanged.
`BW_SESSION=<token> bw ...` was built as a single backtick string. Ruby
handles a leading env assignment itself only when the string has no
shell metacharacters; an escaped item name (e.g. one containing a
space) made it spawn `sh -c` with the session key in the shell's
command line.

Run `bw` via capture_command with BW_SESSION in the environment and the
arguments as an array.
Copilot AI balanced review requested due to automatic review settings October 6, 2026 05:36
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T05:38:46.008904Z b3684c5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@viktorianer

Copy link
Copy Markdown

Small correction to the description: the Bitwarden command reaches /bin/sh -c whenever a session is set, not only with shell metacharacters. Ruby passes a string that starts with a NAME=value assignment to the shell. Where /bin/sh is dash (Debian, Ubuntu), that shell stays alive while bw runs, so ps shows sh -c BW_SESSION=<token> bw get item myitem for a plain item name too. macOS sh and busybox replace themselves with bw, which hides it there. The change already covers both cases.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants