secret get ignores a failed write of the value to stdout and exits 0 #155

Open
opened 2026-10-13 00:38:38 +02:00 by clawbot · 0 comments
Collaborator

Severity: major
A script that redirects secret get to a file sees success with a truncated or empty file; the stored secret is intact.

What happens: GetSecret and GetSecretWithVersion write the value with _, _ = cmd.OutOrStdout().Write(value.Bytes()), so a short write, a full disk, a closed stdout or a broken pipe is neither reported nor reflected in the exit status.

Reproduction, after secret init and echo v | secret add s:

SB_UNLOCK_PASSPHRASE=... secret get s > /dev/full; echo $?   # 0, no error
SB_UNLOCK_PASSPHRASE=... secret get s >&-; echo $?           # 0, no error

secret list has the same shape (_, _ = fmt.Fprintf(out, ...)), but get is the one whose output is the secret.

Where:

_, _ = cmd.OutOrStdout().Write(value.Bytes())
(GetSecret) and
_, _ = cmd.OutOrStdout().Write(value.Bytes())
(GetSecretWithVersion).

Correct behaviour: a write error is returned as the command's error, so the exit status is 1 and stderr says the value could not be written (a broken pipe is the usual exception: the reader went away, and reporting it is optional).

Definition of done

  • secret get s > /dev/full exits 1 with an error naming the write failure; get to a closed stdout exits 1.
  • A test runs get with stdout set to a writer that fails and requires a non-nil error; it fails before the fix.

Model: fable-5-1

Severity: major A script that redirects `secret get` to a file sees success with a truncated or empty file; the stored secret is intact. What happens: `GetSecret` and `GetSecretWithVersion` write the value with `_, _ = cmd.OutOrStdout().Write(value.Bytes())`, so a short write, a full disk, a closed stdout or a broken pipe is neither reported nor reflected in the exit status. Reproduction, after `secret init` and `echo v | secret add s`: ``` SB_UNLOCK_PASSPHRASE=... secret get s > /dev/full; echo $? # 0, no error SB_UNLOCK_PASSPHRASE=... secret get s >&-; echo $? # 0, no error ``` `secret list` has the same shape (`_, _ = fmt.Fprintf(out, ...)`), but `get` is the one whose output is the secret. Where: https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/secrets.go#L446 (`GetSecret`) and https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/secrets.go#L481 (`GetSecretWithVersion`). Correct behaviour: a write error is returned as the command's error, so the exit status is 1 and stderr says the value could not be written (a broken pipe is the usual exception: the reader went away, and reporting it is optional). **Definition of done** - `secret get s > /dev/full` exits 1 with an error naming the write failure; `get` to a closed stdout exits 1. - A test runs `get` with stdout set to a writer that fails and requires a non-nil error; it fails before the fix. Model: fable-5-1
sneak was assigned by clawbot 2026-10-13 00:38:38 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/secret#155