Threat model

Security

msecrets protects secret values at rest in your repository and makes every change to them attributable and reviewable.

Cryptography

What is protected

Confidentiality

Only the private keys of an environment's recipients decrypt its values. The repository, its forks, CI logs of check, and anyone with read access see only ciphertext.

Integrity

Readers verify signatures before decrypting. A value that was edited, moved to another secret, environment, or file, or written by someone outside the environment is rejected.

Least privilege

Access is per environment. Machine keys are read-only. Revocation re-encrypts every affected value or fails, so it can never silently leave access behind.

No hidden state

Who can read what is written in the file and visible in diffs. Keys and identity sources never come from the repository.

Safe to review

The file is plain text, and so is everything msecrets prints from it. Descriptions cannot contain control characters, error messages escape names, and revealed values are sanitized in the terminal UI, so a pull request cannot hide lines from reviewers or write to their clipboard with terminal escape sequences.

Hostile pull requests

Treat the whole msecrets.json of a pull request as attacker-controlled, including who may read and sign. The file cannot prove who a recipient really is; trust starts with the reviewed version on your default branch. Each row is a regression test:

The pull request… Signatures and encryption git diff shows
adds its author as a recipient Reveal nothing; values become needs sync and msecrets check fails. A member’s sync would grant access. the new recipient and the changed access list
replaces a member’s key with its own Every value that member signed becomes invalid. New values signed with the replaced key verify. the member’s key fingerprint changing
restores an older signed value The old value verifies (rollback). the value’s signature line changing
moves or edits values, or claims another signer Rejected: the value is invalid and never decrypted. the changed values
writes with a read-only machine key Impossible: machine keys cannot sign. nothing to review

So review every change to recipients, access, and values, and never run msecrets sync or grant on a pull request you have not reviewed.

Hostile input

Parsers reject everything that is not canonical, and input is bounded: an age header has at most 1024 stanzas and 1 MiB, an environment at most 1024 recipients, and a secrets file at most 64 MiB. Signatures are checked before any value is decrypted, so a forged ciphertext never reaches the age parser.

These are tests, not an audit: the implementation has not had an independent security review yet.

What you must still do

Reporting a vulnerability

Please report security issues privately through GitHub security advisories.