Secret scanning (on by default) π¶
Every TOVIO repo scans for secrets on every commit, out of the box β no install, no configuration.
It is the first-party plugin com.tovio.secret-scan, running in the same capability-bounded sandbox as
any other plugin (Capabilities & security), so it can read the files you're
committing but cannot touch the network, the filesystem, or anything outside the content it's handed.
When it finds a secret, it doesn't silently do something to your repo. It stops and asks you.
What it does¶
On tovio commit, before the snapshot is taken, the scanner looks at the clear (unencrypted) files the
commit introduces. If it flags something, you get a prompt:
$ tovio commit -m "add prod config"
π 1 secret(s) detected in the snapshot
[error] Identified an AWS access key ID paired with a secret access key, which together can provide full access to AWS services. at line 1 (AKIAβ¦EWZZ) (config/prod.conf)
paths: config/prod.conf
Protect these? [E]ncrypt in place (default) / [b]lock / [a]llow-once:
The wording of a finding is the detection rule's own description, and its severity is the rule's β most
credential rules report error. Once your allowlist has vouched for some of a snapshot's findings, the
summary line grows an (N allowlisted) count for the ones it suppressed; if every finding is vouched
the block dissolves and the commit proceeds.
Three choices, and you pick:
- [E]ncrypt in place β TOVIO adds a protective policy for the file and encrypts it as part of this commit. The secret goes into history as ciphertext, readable only by you (and anyone you later grant). This is the recommended default.
- [b]lock β refuse the commit. Nothing is written; fix the file and try again.
- [a]llow-once β commit the file unencrypted, just this once, on your explicit say-so. TOVIO prints
the fingerprints so you can allowlist a confirmed false positive permanently, and records the say-so as a
signed
SecretAllowedOnceentry naming you and those fingerprints β never the raw values. (A Simple repo has no signing identity and therefore no audit chain, so nothing is recorded there.)
The raw secret never appears in output, in an error, or in the audit record β only a redacted preview.
A matched value longer than eight characters shows its first and last four, AKIAβ¦EWZZ; a shorter one
shows only its first two. A rule that fires on the filename rather than on content (a .env file,
say) has no secret to redact, so it previews the filename.
It never acts without a human¶
This is the important part. The scanner proposes; a person confirms. TOVIO will never silently
encrypt a file or wave a secret through on its own. So in any context where there's no human at the keyboard β
CI, an agent (tovio commit --token), --json, --quiet, or a piped stdin β the commit fails closed:
$ printf 'aws_key = "AKIAβ¦"\n' > config/prod.conf
$ tovio commit -m "add config" < /dev/null # non-interactive
β Secrets detected β commit blocked
β¦
Fingerprints (paste into .tovio/secrets-allow.toml `allow = [β¦]` to permanently allow a vouched false positive):
SECRET:aws-access-token:d2c9a035e2eb
β¦
[TVO-SECRET-001]
A bot can only ever block β it can't auto-encrypt and it can't auto-allow. That's the guarantee.
Encrypting needs a team identity
Encrypt-in-place seals the file to your key, so it needs one. In a Simple repo (no cryptographic
identity) the prompt tells you so and offers block / allow-once instead β run
tovio init --mode team to enable encryption.
Handling false positives¶
Real code sometimes looks like a secret. Two ways to vouch for a line:
- Inline β add a
tovio:allow-secretcomment on the flagged line. It travels with the file, so your whole team gets the same suppression. - By fingerprint β every finding has a stable fingerprint (its
code,SECRET:<rule-id>:<hash>, likeSECRET:aws-access-token:d2c9a035e2eb). When a commit is blocked, TOVIO prints it ready to paste into.tovio/secrets-allow.toml:
The fingerprint hashes the exact occurrence β rule, path, line, and value β so an edit that moves or
changes the value re-flags it. Keying on the fingerprint rather than a rule or path also makes the
allowlist swap-proof: any scanner emitting the same code gets the same suppression. The file is local
repo state, never synced, and it is fail-safe: a missing or malformed file suppresses nothing (a
malformed one also warns).
Turning it off, or swapping it¶
Local, per-repo .tovio/config settings:
| Setting | Effect |
|---|---|
secrets.scan = off |
turn default scanning off for this repo (env override: TOVIO_SECRETS_SCAN=off) |
secrets.scanner = <plugin-id> |
swap in a different scanner (any plugin that reads content on pre-snapshot) |
secrets.protect-policy = <expr> |
the read policy "encrypt" writes (default clearance=secrets) |
Keeping plugins on a leash¶
Plugins already run under hard, always-on limits β no network, no filesystem, a compute (fuel) cap of a few CPU-seconds, a 256 MiB memory ceiling, a 4 MiB output cap. So a plugin can't be turned into a free compute farm or hang your commit. If you want to tighten any of that further, you can β per repo:
| Setting | Env override | Caps |
|---|---|---|
plugins.max-timeout-ms |
TOVIO_PLUGIN_MAX_TIMEOUT_MS |
wall-clock time per run |
plugins.max-fuel |
TOVIO_PLUGIN_MAX_FUEL |
compute (instructions) per run |
plugins.max-memory-mb |
TOVIO_PLUGIN_MAX_MEMORY_MB |
memory per run |
Each setting only ever tightens the built-in ceiling β it can't loosen it. And if a plugin blows its budget, it fails closed (a required plugin that times out blocks the commit β it's never silently skipped).
See also¶
- Capabilities & security β the sandbox model these plugins run in.
- Tutorial: protect a secret β the encryption side, hands-on.
- Errors β
TVO-SECRET-001and the plugin block codes. - The normative spec (
docs/specs/secret-scanning.md, REQ-SECRET-*) and the decision record (ADR-0057) in the repository.
Last reviewed September 9, 2026
Suggest an improvement to this page Not for security reports — see disclosure