Development record
Transcript records are written world-readable: history.Capture writes each redacted record with mode 0644 into a transcripts chain ahoy creates 0755 (apply.go), while the unredacted staging tier is 0700/0600 by stated design. Noted by GHSA-gmp7-9rvm-qcr3 as the amplifier of the PEM leak, it is a separate question from the redaction defect: whether a redacted transcript store under the caller home should be private to the account (records 0600 and the chain 0700) or is meant to be readable by other local accounts. No ADR or decision records the choice, the tightening spans the ahoy-owned directory chain, and no consumer is known to rely on a world-readable store. Fork to decide: tighten both (one mode change in history plus one in ahoy, with a test on the resulting mode) or record the world-readable posture as deliberate.
Transcript records are written world-readable: history.Capture writes each redacted record with mode 0644 into a transcripts chain ahoy creates 0755 (apply.go), while the unredacted staging tier is 0700/0600 by stated design. Noted by GHSA-gmp7-9rvm-qcr3 as the amplifier of the PEM leak, it is a separate question from the redaction defect: whether a redacted transcript store under the caller home should be private to the account (records 0600 and the chain 0700) or is meant to be readable by other local accounts. No ADR or decision records the choice, the tightening spans the ahoy-owned directory chain, and no consumer is known to rely on a world-readable store. Fork to decide: tighten both (one mode change in history plus one in ahoy, with a test on the resulting mode) or record the world-readable posture as deliberate.
Grounds
- pursued: a captured record and a migrated one both stat at exactly 0o600 whatever the umask (TestCaptureWritesTheRecordOwnerOnly, TestMigrateNarrowsTheRecordItRewrites, both watched fail at 0644 before the change); a record file written by the store at any wider mode would show it wrong
Frontmatter
| id | iss-2609012029343438 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-2609012029343438-transcript-records-are-written-world.md
open on GitHub ↗ · commit history ↗
mentions1
- iss-2609291610432030The transcript store never narrows what an earlier binary laid out wider: a chain level that already exists keeps its mode (fsutil.EnsureRealDir creates at 0o700 and leaves an existing directory alone, internal/core/history/location.go, Resolve), and a record already on disk at 0o644 stays at 0o644 until Migrate happens to rewrite it. Capture now writes every new record 0o600 (iss-2609012029343438), which protects nothing already stored: on a machine where an earlier layout created ~/.abcd/transcripts or a level below it 0o755, every record captured before the fix stays readable by other local accounts. The remedy is a narrowing pass on the store's own levels only (the base, the root-sha level and records/, never ~/.abcd or a checkout's .abcd/.work.local), each opened O_NOFOLLOW|O_DIRECTORY, owner checked with fstat against this account, and narrowed with fchmod on the descriptor, the shape of fsutil's unexported tightenLock for lock files. No exported fsutil primitive does that for a directory, so it is a new primitive plus a stance change for EnsureRealDir's never-narrow contract, not a mode constant.