Skip to content

fix(example): close the four examples/ review findings - #68

Merged
deadpoets merged 1 commit into
mainfrom
fix/example-password-remanence
Aug 19, 2026
Merged

fix(example): close the four examples/ review findings#68
deadpoets merged 1 commit into
mainfrom
fix/example-password-remanence

Conversation

@deadpoets

@deadpoets deadpoets commented Aug 19, 2026

Copy link
Copy Markdown
Owner

The examples/ module had four open findings and no fixes had touched it. For a
library whose examples are its documentation, that was the largest gap left.

password-logindc28356

  • :69bufio.NewReader().ReadString() left the password in a 4 KiB
    reader buffer and two immutable Go strings. A string cannot be wiped and none
    of those copies were reachable to try, so only the final []byte was erased —
    in the example whose stated point is that the password stops existing.
  • :68 — typed with terminal echo on.

Now read a byte at a time straight into a SecureBuffer, raw mode when stdin is
a TTY. No bufio, no intermediate string, no append growth.

hardened-ssh-agent9a7ffe3

  • :149 — the README claimed parity with ssh-agent, which calls
    getpeereid on every accept. This one served anyone who could reach the
    socket. Peer uid must now equal ours, root excepted, exactly as ssh-agent
    does.
  • :108 — the socket directory was named after the pid. Pids are small and
    enumerable, so a local process could pre-create the directory for likely pids
    and deny the agent a socket. Now MkdirTemp.

Peer credentials come from SO_PEERCRED on Linux and LOCAL_PEERCRED on
darwin/FreeBSD. OpenBSD and NetBSD have no typed accessor in x/sys, so they
refuse to start rather than serve connections they cannot attribute.

Verified

  • password-login run end to end with piped stdin: register, correct login, wrong
    password rejected, EOF with no trailing newline, and >256 bytes rejected
    rather than truncated — truncation would let a prefix log in.
  • TestPeerUID_ReportsOurOwnUID covers the new gate. A broken peerUID would
    reject every connection and present as a networking fault, not a security
    control misfiring. The reject path needs a second uid and is not reachable
    from a test process.
  • Cross-compiles for linux, darwin, freebsd, openbsd, netbsd (amd64 + arm64
    where relevant).
  • On Linux: go vet, go build -mod=readonly, go test -race ./... clean
    under GOWORK=off.

go.mod gains golang.org/x/term and promotes golang.org/x/sys to direct.
The secmem and secmem-crypto require lines are untouched.

bufio + ReadString left the password in a 4 KiB reader buffer and two immutable
strings, none of them wipeable — in the example whose whole point is that the
password stops existing. Read it a byte at a time into a SecureBuffer instead,
with the terminal in raw mode so it is not echoed either.

Review findings password-login/main.go:68 and :69.
@deadpoets
deadpoets merged commit 82b91ce into main Aug 19, 2026
22 checks passed
@deadpoets
deadpoets deleted the fix/example-password-remanence branch August 19, 2026 04:10
@deadpoets deadpoets changed the title fix(example): read the password into secure memory with echo off fix(example): close the four examples/ review findings Aug 19, 2026
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