mint_
Documentation menu
On this page

Project / Documentation

Security model

CSPRNG guarantees, redaction and the limits of the scanner.

This page describes what mint and mint guard actually guarantee, and what they do not.

Randomness#

One entropy source#

Every random byte comes from crypto.randomBytes in node:crypto. There is no Math.random() in the source, no clock-derived fallback, no seed file and no PRNG state to leak.

The random helpers are centralized:

  • randomIntBelow for integers under 2 to the 32.
  • randomBigIntBelow for larger ranges.
  • randomInRange for inclusive integer ranges.
  • sampleChars for character strings.
  • sampleOne and sampleMany for array choices.
  • shuffle for Fisher-Yates shuffles.

Generators are built from those helpers rather than doing their own arithmetic.

No modulo bias#

Mapping a byte onto a 58-symbol alphabet with byte % 58 makes some symbols more likely. mint does not do that.

For a charset of size k, bytes at or above floor(256 / k) * k are rejected and redrawn. Every remaining byte maps to exactly one symbol, so every symbol has probability 1/k. For alphabets that divide 256, such as 16, 32, 64 and 128, nothing is rejected.

Integers use the same idea over 32-bit values. Large integer ranges reject values outside the largest exact multiple of the range. Dice, ports, item picks and Fisher-Yates shuffles all use these primitives.

Entropy accounting#

--entropy and --json report the random bits in the value, not the encoded length:

  • Encoded bytes: 8 bits per byte.
  • Sampled characters: length times log base two of the alphabet size.
  • UUID v4: 122 bits.
  • UUID v7: 74 bits, because the timestamp is not secret.
  • UUID v1: 61 bits.
  • UUID nil: 0 bits.
  • ULID: 80 bits.
  • KSUID: 128 bits.
  • TypeID: 74 bits.
  • Snowflake: 22 bits.
  • ObjectId: 64 bits.
  • Passphrase: 11 bits per word, plus about 6.64 bits for --number.

A value can be unique without being secret. Treat the reported bits as the security-relevant number.

Encoding is not encryption#

Base64 and base58 are encodings. They do not hide a value. The security of a generated value comes from the random bits behind it.

The CLI#

  • No network requests, telemetry, update checks or remote rule feeds.
  • No runtime dependencies. The package ships the compiled CLI and nothing else.
  • No config file, history file or generated secret storage.
  • No execution of repository code while generating or scanning.
  • Values are written to stdout and optionally stderr for entropy and warnings.
  • Colors only appear on a TTY.
  • --copy uses a platform clipboard helper when one is available.

mint guard reads project files and can run read-only git commands. It writes only when you explicitly run init, baseline, install-hook or uninstall-hook.

Redaction#

Findings in text, JSON, SARIF, Markdown and baseline output never contain the raw value.

  • Length 12 or more: first four characters, three periods, last two characters.
  • Length under 12: ***.
  • File-level env findings have no value and show ***.
  • Baseline entries use a salted hash, not a preview.

The scanner keeps the raw match only long enough to compare spans, compute a hash and produce the preview. It is not attached to the finding object.

Baselines#

A baseline hash is:

sha256(salt, rule id, file path, secret)

with NUL separators between fields. The salt is random and stored in the baseline file. Without the salt, the hashes cannot be compared against a list of known secrets. The file does not reveal a value, but it does prove that some value was accepted at a point in time.

What mint does not do#

  • It does not encrypt, decrypt or manage keys.
  • It does not generate RSA or EC key pairs. Use ssh-keygen, openssl or a platform keystore.
  • It does not check password strength or breach lists.
  • It does not implement BIP-39 mnemonics. The bundled list is a word source for passphrases.
  • It does not hide a value from your shell, terminal scrollback, process list, shell history or clipboard manager.
  • It does not store generated values. If you lose one, generate another.
  • mint uuid --nil is deliberately not random and reports zero bits.

What mint guard does not do#

  • It does not prove a repository has no secrets.
  • It does not know whether a value is live, fake or already revoked.
  • It does not scan binary files, files over the size limit or lines over 8 KB.
  • It does not fetch provider key formats or validate a credential online.
  • It does not rotate anything. It prints rotation steps, and --fix prints a plan.
  • It does not rewrite history or edit files.
  • It does not replace secret management, provider-side scanning or access review.

A clean scan is a useful signal, not a security guarantee. A finding is a prompt to rotate, not just delete.

Verification#

The repository includes generator format, charset, uniqueness and uniformity tests, guard rule tests, redaction tests that assert no format leaks a raw secret, and an end-to-end verifier:

npm test
npm run verify

npm run verify drives every generator, flag and output mode through the built CLI. The site's playground is a separate implementation using Web Crypto; it is a demo, not the package's security boundary.