Skip to content

fix(#34): paste-flow bearer-URL log + fnox set via stdin#40

Closed
bglusman wants to merge 1 commit intofeat/secret-paste-web-uifrom
fix/pr34-paste-flow-security
Closed

fix(#34): paste-flow bearer-URL log + fnox set via stdin#40
bglusman wants to merge 1 commit intofeat/secret-paste-web-uifrom
fix/pr34-paste-flow-security

Conversation

@bglusman
Copy link
Copy Markdown
Owner

Summary

Two LEGIT-FIX items from the PR #34 review triage:

  • zeroclawed-secret-paste/src/lib.rs:151 — full paste URL (which contains the one-shot bearer token) was logged at info!, landing in shared logs / journalctl / shell history of any caller that captures stdout. Address-only at info!; URL gated to debug! (opt-in via RUST_LOG).
  • onecli-client/src/fnox_client.rs:174fnox set <name> <value> passed the value as argv, visible in ps//proc to other users on shared hosts. Switched to stdin: argv is now set <name> - and the value flows over the child's stdin pipe.

Test plan

  • cargo test -p onecli-client --lib fnox_client — 11 pass; argv-order test rewritten as set_uses_stdin_for_value_not_argv asserting BOTH absence from argv AND presence on stdin
  • cargo test -p zeroclawed-secret-paste --lib — all 7 pass

Notes

PR #34 still has other LEGIT-FIX items (no graceful shutdown, CLI doesn't exit on submit, Origin: null acceptance) — leaving those for a follow-up to keep the diff focused on the two highest-impact secret-leak fixes.

🤖 Generated with Claude Code

Two LEGIT-FIX items from the PR #34 triage:

1. zeroclawed-secret-paste/src/lib.rs:151 — full paste URL (which
   contains the one-shot bearer token) was logged at info!, landing
   in shared logs / journalctl / shell history of any caller that
   captured stdout. Address-only at info!; URL gated to debug! (opt-in
   via RUST_LOG).

2. onecli-client/src/fnox_client.rs:174 — `fnox set <name> <value>`
   passed the value as argv, visible in `ps`/`/proc` to other users on
   shared hosts. Switched to stdin: argv is now `set <name> -` and
   the value flows over the child's stdin pipe.

The argv-order test was rewritten to assert BOTH that the value is
absent from argv AND that it arrives on stdin — an explicit guard
against future regression.
Copilot AI review requested due to automatic review settings April 25, 2026 04:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves secret-handling security in the workspace by reducing accidental leakage of bearer tokens and secret values via logs and process listings.

Changes:

  • Adjust zeroclawed-secret-paste logging to avoid emitting the full one-shot URL (token) at info!, keeping it at debug! only.
  • Update FnoxClient::set to send secret values over stdin (fnox set <name> -) instead of argv.
  • Update FnoxClient tests to assert the value is absent from argv and present on stdin.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
crates/zeroclawed-secret-paste/src/lib.rs Prevents leaking one-shot bearer tokens via info! logs by logging only the bound address.
crates/onecli-client/src/fnox_client.rs Prevents leaking secret values via process args by switching fnox set to stdin and strengthening tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +185 to 195
if let Some(mut stdin) = child.stdin.take() {
stdin
.write_all(value.as_bytes())
.await
.map_err(FnoxError::NotInstalled)?;
// Drop closes stdin so fnox sees EOF.
}
let output = child
.wait_with_output()
.await
.map_err(FnoxError::NotInstalled)?;
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

write_all(..) and wait_with_output() I/O failures are currently mapped to FnoxError::NotInstalled, which will produce a misleading “install fnox” message for cases like broken pipe (fnox exits early due to bad args/version), permission errors, or other runtime I/O issues. Consider introducing a distinct error variant for subprocess I/O (or mapping these to FnoxError::Failed after capturing stderr) so operators get the real underlying failure reason.

Copilot uses AI. Check for mistakes.
Comment on lines +380 to +384
&format!(
r#"echo "$1 $2 $3" > {} ; cat > {} ; exit 0"#,
argv_log.display(),
stdin_log.display()
),
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fake-fnox shell snippet writes logs using unquoted paths from argv_log.display()/stdin_log.display(). If the temp dir path contains spaces or shell-significant characters, the test can fail unexpectedly. Quote/escape the paths in the generated script to make the test robust.

Copilot uses AI. Check for mistakes.
bglusman added a commit that referenced this pull request Apr 25, 2026
…ning (#44)

Squash-merge of integration/super-combined — 4 weeks of feature work + cross-PR security
fixes + codex agent's hardening, all green CI (14/14 checks).

## Features landing
- **fnox secret-resolver integration** (#15) + FnoxClient subprocess wrapper (#21)
- **Adversarial commit-reviewer + mechanical pre-commit gate** (#18)
- **{{secret:NAME}} substitution engine** in security-proxy URL/headers/body (#19)
- **Per-secret destination allowlist** (#22) — RFC §11.1 attack defense
- **!secure chat commands** (set/list) on Telegram (#20), Matrix (#28), WhatsApp (#31)
- **zeroclawed-mcp** scaffold — agent-facing secret discovery server (#23)
- **install.sh wires MCP** into Claude Code agent configs (#26)
- **zeroclawed-secret-paste** — localhost web UI for one-shot secret input (#34)
- **Bulk paste UI** — .env-style multi-secret onboarding with per-line results
- **LAN-friendly defaults** — bind 0.0.0.0 + RFC 1918 Origin acceptance
- **WhatsApp HMAC verification** (was always-true placeholder before — codex hardening)

## Security fixes folded in
- /vault/:secret bearer auth + 127.0.0.1 default bind (#39)
- URL-embedded secrets honor destination allowlist (#41)
- Paste-flow: bearer URL only at debug, fnox set via stdin not argv (#40)
- Paste-flow: graceful shutdown, exit-on-submit, reject Origin: null (#43)
- Subprocess timeouts + kill_on_drop on FnoxClient
- BrokenPipe-tolerant stdin write (Linux CI surface)
- Header-value log redaction
- OneCLI bound to 127.0.0.1 by default
- Sanitized real API token + Telegram IDs from sample configs (#36)

## Architecture / refactors
- Consolidated onecli binary into security-proxy (#17)
- Hardcoded vault URL removed from onecli-client
- security-proxy resolver wired into hot path
- Extracted build_app router; migrated /vault/:secret route
- !secure parser uses split_whitespace (was splitn), audit-logs invocations

## Test coverage added
- security-proxy substitution engine + body/headers tests
- onecli-client retry + Http(_) variant + adversarial fallthrough suite
- onecli-client client.rs rewritten from tautologies to wiremock-backed
- config/validator coverage (was zero, now 290-line module covered)
- 16 zeroclawed-secret-paste tests including bulk-mode cases

## Docs / RFCs
- agent-secret-gateway holistic architecture
- consolidation-findings (what #28 must address)
- secret-input-web-ui RFC (input-only, new-by-default)
- browser-harness integration spike
- test-quality-audit Round 1+2+3 (host-agent + zeroclawed priority files)

## Codex agent's hardening cherry-picks
- Subprocess timeouts on fnox calls
- map_spawn_error helper
- Validator hardening + atomic-counter digest race fix
- WhatsApp HMAC implementation + tests
- proxy header-value log redaction

CI: all 14 checks green at squash time.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@bglusman
Copy link
Copy Markdown
Owner Author

Subsumed by #44 (squashed to 9ed51fbc on main). All commits from this branch are present in the squash. Closing as redundant rather than merging again.

@bglusman bglusman closed this Apr 25, 2026
bglusman added a commit that referenced this pull request Apr 25, 2026
…ning (#44)

Squash-merge of integration/super-combined — 4 weeks of feature work + cross-PR security
fixes + codex agent's hardening, all green CI (14/14 checks).

## Features landing
- **fnox secret-resolver integration** (#15) + FnoxClient subprocess wrapper (#21)
- **Adversarial commit-reviewer + mechanical pre-commit gate** (#18)
- **{{secret:NAME}} substitution engine** in security-proxy URL/headers/body (#19)
- **Per-secret destination allowlist** (#22) — RFC §11.1 attack defense
- **!secure chat commands** (set/list) on Telegram (#20), Matrix (#28), WhatsApp (#31)
- **zeroclawed-mcp** scaffold — agent-facing secret discovery server (#23)
- **install.sh wires MCP** into Claude Code agent configs (#26)
- **zeroclawed-secret-paste** — localhost web UI for one-shot secret input (#34)
- **Bulk paste UI** — .env-style multi-secret onboarding with per-line results
- **LAN-friendly defaults** — bind 0.0.0.0 + RFC 1918 Origin acceptance
- **WhatsApp HMAC verification** (was always-true placeholder before — codex hardening)

## Security fixes folded in
- /vault/:secret bearer auth + 127.0.0.1 default bind (#39)
- URL-embedded secrets honor destination allowlist (#41)
- Paste-flow: bearer URL only at debug, fnox set via stdin not argv (#40)
- Paste-flow: graceful shutdown, exit-on-submit, reject Origin: null (#43)
- Subprocess timeouts + kill_on_drop on FnoxClient
- BrokenPipe-tolerant stdin write (Linux CI surface)
- Header-value log redaction
- OneCLI bound to 127.0.0.1 by default
- Sanitized real API token + Telegram IDs from sample configs (#36)

## Architecture / refactors
- Consolidated onecli binary into security-proxy (#17)
- Hardcoded vault URL removed from onecli-client
- security-proxy resolver wired into hot path
- Extracted build_app router; migrated /vault/:secret route
- !secure parser uses split_whitespace (was splitn), audit-logs invocations

## Test coverage added
- security-proxy substitution engine + body/headers tests
- onecli-client retry + Http(_) variant + adversarial fallthrough suite
- onecli-client client.rs rewritten from tautologies to wiremock-backed
- config/validator coverage (was zero, now 290-line module covered)
- 16 zeroclawed-secret-paste tests including bulk-mode cases

## Docs / RFCs
- agent-secret-gateway holistic architecture
- consolidation-findings (what #28 must address)
- secret-input-web-ui RFC (input-only, new-by-default)
- browser-harness integration spike
- test-quality-audit Round 1+2+3 (host-agent + zeroclawed priority files)

## Codex agent's hardening cherry-picks
- Subprocess timeouts on fnox calls
- map_spawn_error helper
- Validator hardening + atomic-counter digest race fix
- WhatsApp HMAC implementation + tests
- proxy header-value log redaction

CI: all 14 checks green at squash time.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.

2 participants