Skip to content

Windows: encrypt credentials at rest via DPAPI #27

Description

@Taure

Summary

On Windows, ~/.asobi/credentials.json (access token, refresh token, device secret) is stored as plaintext JSON. The 0o600/0o700 modes we pass to os.WriteFile/os.MkdirAll only set the read-only attribute on Windows -- they do not create an ACL. The file is protected only by the ACL it inherits from the user profile (owner + SYSTEM + Administrators).

This is not an exploitable weakness on a default install: other unprivileged users cannot read another user's profile, which matches the Unix 0600 guarantee for that threat (there, root can read it too). It's a defense-in-depth gap -- on Unix the mode is an explicit per-file guarantee, while on Windows we rely on inherited directory ACLs and keep the tokens in the clear.

Proposed hardening

Encrypt the credential blob at rest on Windows with DPAPI (CryptProtectData / CryptUnprotectData, available via golang.org/x/sys/windows), scoped to the current user (CRYPTPROTECT_UI_FORBIDDEN). This ties the ciphertext to the logged-in user account, so an Administrator or SYSTEM read of the raw file yields ciphertext, not tokens.

Notes

  • Leave the Unix path unchanged -- 0600/0700 is the idiomatic guarantee there.
  • Gate the DPAPI code behind //go:build windows so the dependency and syscalls don't touch other platforms.
  • Optional follow-up for parity: macOS Keychain / libsecret on Linux. DPAPI is the highest-value first step since it needs no external daemon or keyring.
  • Prior art: gh, aws, and gcloud all encrypt or OS-keyring their stored credentials.

Follow-up to the per-platform wording fix in SECURITY.md.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions