Skip to content

[Yun Tianming] src/commands/secrets.ts: secrets pull writes .env at umask default mode #240

Description

@Fermionic-Lyu

Location: src/commands/secrets.ts:109-110.

Kind: insecure file permissions.

Impact: The whole branch secret bundle (DB DSNs, provider keys) is written to .env (or -o <file>) with writeFile(out, serializeEnv(bundle)) and no mode, so it lands at 0644 under umask 022. The command's own tip ("credentials must never be committed") shows the git threat model is understood; the filesystem one is not.

Evidence:

const out = opts.output ?? '.env'
await writeFile(out, serializeEnv(bundle))

Fix would touch: this write only: { mode: 0o600 } plus chmod for a pre-existing file (create-only caveat), and consider preserving a stricter existing mode on -o <file> the way src/commands/storage.ts:127-129 does for downloads.


Found by Yun Tianming: nightly sweep 2026-09-17-1000 at ecfe5168a32e. Report only; no code was changed for this finding.

🤖 Generated with Claude Code


Issue cleanup — 2026-09-29

Canonical tracker for duplicate #273, closed during this cleanup. The defect remains open. Preserve #273’s additional observation about symlink-following when deciding the output-file write contract.

Activity

  1. Fermionic-Lyu commented on Oct 2, 2026

    @Fermionic-Lyu
    MemberAuthor

    Deferred on review scope/behavior choice; PR #341 remains open.

    The implementation restricts the opened file descriptor before writing, preserves stricter existing permissions (e.g. 0200), and preserves current inode/symlink behavior. Typecheck and all 1,999 local tests passed. Independent review found no production defect.

    Wang Miao requests replacing it with writeFileAtomicSync(..., { mode: 0o600 }). That helper exists and provides atomic replacement, but it is not behavior-equivalent: it replaces the inode and forces 0600, including widening a stricter 0200 output. The original #240 explicitly asks to consider retaining stricter output modes. Atomic replacement could also change hard-link behavior; the current write follows the existing target/inode contract.

    The concrete choice is whether secrets output should retain stricter permissions and inode behavior, or adopt the repository's atomic-replacement helper with its fixed-mode contract. This cleanup batch will not settle that disagreement or expand the shared helper. Leaving the issue/PR open, recording the options here, and moving on without another review round or merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions