Skip to content

fix(sdk): compute_auth_tag reads the owner secret from a file or stdin, never argv - #7699

Open
rmichelena wants to merge 1 commit into
block:mainfrom
rmichelena:bumble/compute-auth-tag-no-argv
Open

rmichelena wants to merge 1 commit into
block:mainfrom
rmichelena:bumble/compute-auth-tag-no-argv

Conversation

@rmichelena

Copy link
Copy Markdown

Summary

crates/buzz-sdk/examples/compute_auth_tag.rs mints the NIP-OA auth tag an agent needs, and it took the owner's secret key as a positional argument. Anything on argv is readable through /proc/<pid>/cmdline by every local user for the life of the process, and the natural invocation (-- $(cat owner.key) <pubkey>) also routes the secret through a shell expansion. This runs on the owner's host — the one place the owner key must not leak.

This PR makes the secret arrive only through --owner-key-file <path> or --owner-key-stdin. The agent pubkey stays positional; --conditions becomes a flag.

  • The old positional form is refused before anything else happens, without echoing its arguments, so a script still passing the secret on argv fails loudly instead of silently working.
  • A bech32 nsec anywhere on argv is refused for the same reason. (A 64-hex secret and a 64-hex x-only pubkey have the same shape, so the old hex form is caught by argument count rather than by sniffing.)
  • No error message includes what was read.
cargo run --release --example compute_auth_tag -- --owner-key-file owner.key <agent_pubkey_hex>
cargo run --release --example compute_auth_tag -- --owner-key-stdin <agent_pubkey_hex> < owner.key

Compatibility

Breaking for anyone invoking the example with the secret on argv — deliberately: that invocation is the leak. Nothing in the repository does (grep over *.md, *.sh, *.py, *.ts, *.yml; the benchmarks/.../test_keys.py comment only cites this file for its fixture values). Same tag output as before for the same inputs.

Test plan

  • cargo test -p buzz-sdk --example compute_auth_tag — 5 passed: file form and stdin form produce a tag that verifies against the owner pubkey; the old form is refused and the refusal does not echo the secret; missing source / missing pubkey; empty source.
  • cargo fmt -p buzz-sdk -- --check, cargo clippy -p buzz-sdk --example compute_auth_tag -- -D warnings clean.
  • In production use on a closed relay since 2026-09-15 (owner-side tag minting for a headless agent), applied as a source patch on 3c7f288c; this is the same change rebased on main@6dfd145cd.

🤖 Generated with Claude Code

…n, never argv

The example that mints a NIP-OA auth tag took the owner's secret key as
its first positional argument. Anything on argv is readable by every
local user through /proc/<pid>/cmdline for the life of the process, and
the documented invocation -- `-- $(cat owner.key) <pubkey>` -- also puts
the secret through a shell expansion. The tag is computed on the owner's
host, which is exactly where the owner key must not leak.

The secret now arrives through `--owner-key-file <path>` or
`--owner-key-stdin`; the agent pubkey stays positional; `--conditions`
is a flag. The pre-change positional form is refused before anything
else happens, and the refusal does not echo its arguments, so a script
that still passes the secret on argv fails loudly instead of working.
A bech32 nsec anywhere on argv is refused for the same reason (a 64-hex
secret and a 64-hex x-only pubkey have the same shape, so the old form
is caught by its argument count instead). No error message includes
what was read.

Tests (cargo test -p buzz-sdk --example compute_auth_tag): file and
stdin forms produce a tag that verifies against the owner pubkey; the
old form is refused without echoing the secret; missing source or
pubkey; empty source. Nothing else in the repository invokes this
example with the old form (grep of *.md, *.sh, *.py, *.ts, *.yml).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
@rmichelena
rmichelena requested a review from a team as a code owner September 17, 2026 01:07
@github-actions

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 6dfd145cde4bf0d45091de1cc5e6c7e3462d5703...0b1a6afa5e330b5292ddb174c2fd36940439b877.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 0b1a6afa5e330b5292ddb174c2fd36940439b877 to authorize a new review.
Any previous review applies only to its recorded range.

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.

1 participant