Skip to content

Releases: AISolutionLabs/secret-scanner

Release v1.2.0

Choose a tag to compare

@anirudhkoutha anirudhkoutha released this 17 Oct 22:08
c56fc5c

Changelog

All notable changes are listed here. The project follows
Semantic Versioning; see docs/compatibility.md
for what counts as a breaking change.

Unreleased

  • Release verification is a reusable workflow (verify-release.yml):
    release.yml calls it after publishing, and it can be run by hand for
    any published tag. Its Windows smoke test failed on v1.1.0 although the
    binary behaved correctly (pwsh ends a step with the last native exit
    code, here the expected 1 from blocking a secret); fixed, and the same
    test now runs in CI on every push.
  • The CI templates (ci/github-actions.yml, ci/azure-pipelines.yml)
    publish SARIF, so they now pass SECRETSCAN_HASH_KEY from the CI secret
    store: published fingerprints are keyed once the secret is defined (plain
    SHA-256, as before, until then; Azure warns).
  • A hash key that looks like an unexpanded CI variable ($(...),
    ${{ ... }}, ${...}) is refused: an undefined variable's literal text
    is public and must not become the key.
  • README: fingerprints are documented as sensitive metadata; reports
    without a key should not be published where people who may not see the
    secrets can read them.

1.1.0 - 2026-10-17

The first release with published binaries. The v1.0.0 GitHub release was
created by hand before the release workflow ran, so it has no binaries,
checksums or signatures (go install ...@v1.0.0 works); install v1.1.0
instead. Detection is unchanged from 1.0.0: the detection-code fingerprint
the benchmark was measured on is identical.

Fixes

  • triage chose a trufflehog finding's source location in Go map order
    when its SourceMetadata named several (for example Filesystem and
    Git), so it could check a different file or commit on each run. Entries
    are now read in a fixed order and used only when they agree, or when
    exactly one matches the report's SourceName; otherwise the finding stays
    uncorroborated, its evidence lists the conflicting locations, and no
    source is read for it.
  • Output files are never written through a link: reports, fix patches,
    hooks and --fix rewrites go to a new file in the destination directory
    that is renamed into place. A symlink at a report or patch path is refused
    (terminal and pipe links such as /dev/stdout still work), a symlinked
    hook is replaced by a regular file, --fix skips symlinked sources, and a
    failed report write leaves no partial file.
  • triage --max-report-megabytes N (default 256): a larger report, from a
    file or stdin, is rejected before parsing with exit 2.

Added

  • Keyed secret fingerprints: with SECRETSCAN_HASH_KEY (or
    --hash-key-file, at least 16 bytes), every fingerprint written to a
    report (JSON and CSV SecretHash, SARIF partialFingerprints) is
    hmac-sha256:<hex>, which cannot be tested against guesses without the
    key. Keyed ignore entries and keyed baselines match with the same key;
    plain sha256: entries keep working. Without a key reports still carry
    the plain SHA-256, now documented as guessable for weak secrets.
  • Tests that no raw secret (a weak password, a provider token, a generic
    key, URL credentials, a private key) appears in any report format, the
    suppression ledger, the summary, report files or triage output.

Benchmark integrity and confidence semantics

  • Every published benchmark figure (README, docs, CHANGELOG, release notes,
    install-hook) is generated from bench/results/latest.json, and CI
    checks each one against the row it comes from in the dated results file.
    It also rejects any percentage published outside a generated passage, and
    any balanced figure that does not name its testFixtures setting. This
    fixed stale figures: trufflehog in the README (an earlier full-dataset
    run), detect-secrets' leaky-repo extra lines, two CHANGELOG lines, and a
    triage figure that had no source row.
  • bench/breakdown.py: precision by confidence, path, context, detector
    family and policy, from the holdout report, with detection and blocking
    recall separately. Confidence is documented in the CLI help, the SARIF
    output (tool.driver.properties.confidenceScale) and docs/precision.md as
    a qualitative evidence level, not a probability.
  • Every provider-format rule (86) is tested at test, fixture, example and
    doc paths, .env.example and compose files: none is downgraded or stops
    blocking under balanced (TestNoProviderFormatDowngradedByLocation).
  • docs/benchmark-policy.md:
    labels used as given, a register of label disagreements (AWS WAF
    ChangeToken) reported only as a secondary figure, and a protocol for a
    second independent benchmark. The detection-code fingerprint is recorded
    with the figures, and a release fails if they were measured on different
    detection code. bench/score_labeled.py scores any line-labeled corpus.

Release

  • The release workflow publishes into a release that already exists (one
    created by hand on GitHub) instead of failing: it uploads the binaries,
    checksums and signature and sets the notes. CONTRIBUTING.md documents
    releasing: push the tag only.

1.0.0 - 2026-10-17

First public release: 136 rules, gitleaks-compatible config and reports,
staged/push/history/diff scanning, git hooks, placeholder and local-credential
recognition, noise filters with a suppression ledger, confidence levels and
strict/balanced policies, triage for other scanners' reports, live
verification, remediation guidance and explain. Benchmark results:
bench/results/2026-10-17.md
(earlier rounds: 2026-10-15, 2026-10-16).

Placeholders, local credentials and new detectors

Designed on CredData's dev half, measured once on its test half: precision
83.7% -> 91.5%, recall 48.0% -> 59.2% on repositories never used for design.

  • Placeholder credentials (some_password, s3krit-password, admin123,
    postgres:postgres@) are dropped with a ledger reason
    (placeholder-vocabulary, echoes-key-name, user-equals-password);
    so are digests under hash keys, .NET PublicKeyTokens, translated UI
    strings, algorithm names, crypto test-vector key names and patterned hex.
    Word+number passwords other than one-word defaults are still reported.
  • New Context field (local / example): credentials for localhost,
    private networks, *.local and compose service hosts, and values in
    docker-compose files, .env.example and .env.test, are reported at low
    confidence and listed for review under balanced (strict still blocks).
    URL credentials to local hosts were previously allowlisted silently.
  • New detectors: HTTP Authorization: Basic (only when it decodes to
    user:password) and Bearer headers, SQL CREATE/ALTER USER ... PASSWORD
    and IDENTIFIED BY, NAME_PASSWORD= in compose files, docker -e, ENV and
    inline env, command-line passwords (curl -u, sshpass -p, mysql -p,
    openssl pass:), password calls (setPassword, SetBasicAuth,
    NetworkCredential) and token setters (SetAuthToken).
  • UUIDs under credential-named keys are reported at low confidence; UUIDs
    under request, correlation, paging and concurrency keys (including AWS WAF
    ChangeToken, which grants no access) are not.
  • password-assignment matches indexers (["password"] =), comparisons,
    wrapper calls and 4-5 character values; UI labels under password keys are
    filtered.
  • Rules can declare content validators (basic-auth, opaque-token); a
    value that fails validation never becomes a finding.

Fixes from an external code review

  • triage enforces its 8 MiB source limit while reading: working-tree
    files are size-checked before reading and read through a capped reader;
    history blobs are size-checked with git cat-file -s and streamed with a
    cap, so a huge file named in a report can no longer exhaust memory.
  • --verify checks each secret once per run even under concurrency
    (in-flight requests are shared), and only a provider's documented success
    shape verifies (login for GitHub, object: balance for Stripe,
    data.viewer.id for Linear, ...): JSON error objects, empty documents and
    malformed bodies are unverified. 403 is no longer treated as verified.
    GitHub App installation tokens are checked against
    /installation/repositories.
  • README, docs and the install-hook message take their benchmark figures
    from bench/results/latest.json (bench/render_docs.py); CI fails if a
    published figure is stale.

Fixes from an adversarial recall and security review

  • One-word default passwords plus digits (admin@123, Welcome@2024,
    P@ssw0rd2023, Password1) under password keys are reported at low
    confidence outside test, example and doc files instead of being dropped
    as placeholders (still dropped there, ledger reason
    default-password-in-test-or-doc).
  • Local context no longer applies to Kubernetes service DNS
    (*.svc.cluster.local), other multi-label .local names
    (sql01.corp.local), .env.local / .env.*.local, or any path with a
    prod/production/prd/live segment.
  • redis://:password@host (empty user) is reported by url-credentials.
  • Placeholder phrases must be the whole value: mysecretkey_8f2kq and
    yourkey_<random> are reported.
  • Unquoted values in .env.*.*, .envrc, Makefiles, systemd units and
    .txt files are literals: random base64 there was dropped as
    operator-in-code about 40% of the time. Base64 starting with / or +
    is matched by generic-api-key.
  • Digit-free Bearer tokens (long, mixed case, high entropy) are reported;
    Authorization: <uuid> counts as a c...
Read more

secretscan v1.1.0

Choose a tag to compare

@anirudhkoutha anirudhkoutha released this 17 Oct 21:18
b654bf1

secretscan 1.1.0 is the first release with published binaries. It is a
precision-first secret scanner shipped as a single Go binary with no
dependencies. It scans files, git history, staged changes, outgoing pushes
and raw diffs. The aim is to find more real credentials than existing
scanners without the noise that leads developers to bypass the hook.

The v1.0.0 release on GitHub was created by hand before the release
workflow ran, so it has no binaries or signatures. Use 1.1.0. Detection is
identical to 1.0.0, so the benchmark below applies to both.

New since 1.0.0

  • Deterministic trufflehog triage. A trufflehog finding whose metadata
    names several source locations that disagree is no longer checked
    against whichever one Go's map order produced. It stays uncorroborated,
    with the conflicting locations listed, unless exactly one matches the
    report's own source.
  • Keyed fingerprints. Set SECRETSCAN_HASH_KEY (or --hash-key-file)
    and every fingerprint in a report becomes hmac-sha256:<hex>. Without a
    key, reports carry the plain SHA-256 of each secret, which is enough to
    confirm a guessed weak password, so treat such reports as secrets.
  • Output files are never written through a link. Reports, fix
    patches, hooks and --fix edits go to a new file that is renamed into
    place; a symlink at a report path is refused.
  • Bounded triage input. Reports larger than --max-report-megabytes
    (default 256) are rejected before parsing.
  • Benchmark integrity. Every published figure is generated from one
    results file and checked against the measurement it comes from;
    confidence is documented as an evidence level, not a probability.

Highlights

  • Evidence-based detection. There are 136 built-in rules. Provider
    formats (AWS, Azure, GCP, GitHub, GitLab, Slack, Stripe, OpenAI,
    Anthropic, private keys, ...) are high confidence on their own. A
    generic match needs several independent signals, and every finding
    carries a confidence level and its reasons.
  • Recognises dummies and local credentials. Placeholders
    (some_password, postgres:postgres@, values that repeat their key
    name) are filtered. Credentials for localhost, private networks and
    compose services, and values in .env.example, are reported at low
    confidence for review instead of blocking.
  • No silent passes. Every filtered candidate is counted and can be
    listed with its reason (--show-suppressed).
  • Strict or balanced policy. Strict blocks every finding and is the
    default for scans and CI. Balanced is the default for git hooks: it
    blocks high- and medium-confidence findings and generic values in test
    files, and lists weak evidence under "Needs review". Provider tokens
    block everywhere, including in tests/.
  • secretscan triage. The same precision layer applied to gitleaks,
    trufflehog or any SARIF report. It reads source only inside --root,
    reads history findings at their commit, and never drops a finding
    silently.
  • Fix guidance. Every finding says how urgent it is and how to rotate
    it. --fix-patch writes a reviewable patch that replaces literals with
    environment lookups, and secretscan explain shows loading patterns
    for env, Vault, AWS, Azure and GCP.
  • Optional live verification (--verify, off by default) for 12
    providers. Only a provider's documented success response counts as
    verified.
  • Drop-in gitleaks compatibility. The config schema, fingerprints,
    .gitleaksignore, gitleaks:allow and the JSON report shape all carry
    over.
  • Reports in text, JSON, SARIF 2.1.0, CSV, JUnit XML and an anonymised
    stats summary.

Benchmark

Samsung CredData, 181 repositories never used for design
(secrets-only labels, default settings):

Tool Precision Recall F1
secretscan 1.1.0 91.5% 59.2% 0.719
gitleaks 91.8% 28.9% 0.440
gitleaks + secretscan triage 93.6% 27.5% 0.425
trufflehog 3.97.9 (--no-verification) 44.7% 3.4% 0.064

secretscan matches gitleaks' precision on these repositories and finds
twice as many of the labelled secrets. With the hook default (balanced,
testFixtures = "block"), 39.9% of the labelled secrets block, at 90.2%
precision; strict blocks all 59.2% it reports. On the half of CredData used
for design, secretscan reaches 98.8% precision and 89.0% recall. The gap
between the two halves shows how much of the tuning carries over to
repositories it has not seen. trufflehog was run without verification, so
its recall reflects detector coverage, not its usual verified-only workflow.

Full method, per-class misses and false positives:
bench/results/2026-10-17.md.
Every number can be regenerated with bench/reproduce.sh or the
benchmark workflow in a fork. How the figures are produced, how label
disagreements are handled and how to run a second independent benchmark:
docs/benchmark-policy.md.
Precision by confidence level, path, detector family and policy is in
section 6 of the results file.

Install

Linux and macOS (amd64, arm64):

curl -fsSL https://raw.githubusercontent.com/AISolutionLabs/secret-scanner/main/install.sh | sh -s -- v1.1.0

Windows (PowerShell):

irm https://raw.githubusercontent.com/AISolutionLabs/secret-scanner/main/install.ps1 | iex

With Go 1.24+:

go install github.com/AISolutionLabs/secret-scanner/cmd/secretscan@v1.1.0

As a pre-commit hook: use rev: v1.1.0 with the repository's
.pre-commit-hooks.yaml, or run secretscan install-hook --type both.

The installers check the binary against SHA256SUMS and install nothing
if it does not match. With cosign installed they also check the Sigstore
signature; set SECRETSCAN_REQUIRE_SIGNATURE=1 to make that check
mandatory.

Assets

File Platform
secretscan-linux-amd64, secretscan-linux-arm64 Linux
secretscan-darwin-amd64, secretscan-darwin-arm64 macOS
secretscan-windows-amd64.exe, secretscan-windows-arm64.exe Windows
SHA256SUMS SHA-256 of every binary
SHA256SUMS.sigstore.json Keyless Sigstore signature of SHA256SUMS, bound to this repository's release workflow and tag

Every binary also has a GitHub build-provenance attestation. To verify a
download by hand:

cosign verify-blob SHA256SUMS --bundle SHA256SUMS.sigstore.json \
  --certificate-identity-regexp '^https://github.com/AISolutionLabs/secret-scanner/\.github/workflows/release\.yml@refs/tags/v' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum --ignore-missing -c SHA256SUMS
gh attestation verify secretscan-linux-amd64 --repo AISolutionLabs/secret-scanner

After publishing, the release workflow installs this release from scratch
on clean Linux, macOS and Windows runners and checks that it blocks a
freshly generated token.

Security hardening

The code went through an internal security audit, an adversarial review
and several external code reviews. Every finding is fixed, each with a
regression test that fails on the earlier code. Full list:
docs/security-audit.md.

  • Outputs: reports, fix patches, hooks and --fix edits are never
    written through a symlink or hard link. They are created as a new file
    with mode 0600 and renamed into place.
  • Resource limits: triage limits the reports it reads
    (--max-report-megabytes, default 256) and the source files and
    history blobs they name (8 MiB). Inputs too large to scan are listed in
    the summary instead of passing silently.
  • Verification: --verify sends each secret only to a hard-coded
    provider endpoint, does not follow redirects, and checks each secret
    once per run. It never reports a proxy's page, a JSON error or a 403 as
    "verified".
  • --fix: edits need confirmation or --yes, are syntax-checked, and
    are never applied inside comments, multi-line strings or constant
    positions.

Known limitations

  • 41% of CredData's labelled secrets on unseen repositories are not
    found (59.2% recall). Balanced trades recall for fewer interruptions
    (39.9% of labelled secrets block with the default testFixtures = "block");
    use strict where that matters more.
  • In its default conservative mode, triage drops 54 of gitleaks'
    1,110 true findings on unseen repositories. 41 of those are AWS WAF
    ChangeToken values, which are deliberately not treated as
    credentials (label policy).
  • Confidence levels measure the strength of the evidence, not the
    probability that a value is a credential. On CredData, low-confidence
    findings are the most precise, mostly because CredData labels test
    fixtures as real secrets.
  • Verification sends the secret to its provider. It is off by default and
    should not run from a commit hook.
  • Not yet shown: a second independently labelled corpus, an outside
    reproduction of the benchmark, and dismissal rates from real users.
    Contributions of any of these are welcome.

Compatibility

secretscan follows Semantic Versioning.
docs/compatibility.md
defines what is stable: the CLI flags, exit codes, report formats, config
schema and fingerprints.

Full changelog: CHANGELOG.md

secretscan v1.0.0

Choose a tag to compare

@anirudhkoutha anirudhkoutha released this 17 Oct 08:06
92bf5d1

Changelog

All notable changes are listed here. The project follows
Semantic Versioning; see docs/compatibility.md
for what counts as a breaking change.

1.0.0 - 2026-10-17

First public release: 136 rules, gitleaks-compatible config and reports,
staged/push/history/diff scanning, git hooks, placeholder and local-credential
recognition, noise filters with a suppression ledger, confidence levels and
strict/balanced policies, triage for other scanners' reports, live
verification, remediation guidance and explain. Benchmark results:
bench/results/2026-10-17.md
(earlier rounds: 2026-10-15, 2026-10-16).

Placeholders, local credentials and new detectors

Designed on CredData's dev half, measured once on its test half: precision
83.7% -> 91.5%, recall 48.0% -> 59.2% on repositories never used for design.
Under balanced (testFixtures = "block"), 39.9% of labeled secrets block at
90.2%; gitleaks + triage loses 54 of gitleaks' 1,110 true findings (41
ChangeToken) and removes 27 of its 99 false positives.

  • Placeholder credentials (some_password, s3krit-password, admin123,
    postgres:postgres@) are dropped with a ledger reason
    (placeholder-vocabulary, echoes-key-name, user-equals-password);
    so are digests under hash keys, .NET PublicKeyTokens, translated UI
    strings, algorithm names, crypto test-vector key names and patterned hex.
    Word+number passwords other than one-word defaults are still reported.
  • New Context field (local / example): credentials for localhost,
    private networks, *.local and compose service hosts, and values in
    docker-compose files, .env.example and .env.test, are reported at low
    confidence and listed for review under balanced (strict still blocks).
    URL credentials to local hosts were previously allowlisted silently.
  • New detectors: HTTP Authorization: Basic (only when it decodes to
    user:password) and Bearer headers, SQL CREATE/ALTER USER ... PASSWORD
    and IDENTIFIED BY, NAME_PASSWORD= in compose files, docker -e, ENV and
    inline env, command-line passwords (curl -u, sshpass -p, mysql -p,
    openssl pass:), password calls (setPassword, SetBasicAuth,
    NetworkCredential) and token setters (SetAuthToken).
  • UUIDs under credential-named keys are reported at low confidence; UUIDs
    under request, correlation, paging and concurrency keys (including AWS WAF
    ChangeToken, which grants no access) are not.
  • password-assignment matches indexers (["password"] =), comparisons,
    wrapper calls and 4-5 character values; UI labels under password keys are
    filtered.
  • Rules can declare content validators (basic-auth, opaque-token); a
    value that fails validation never becomes a finding.

Benchmark integrity and confidence semantics

  • Every published benchmark figure (README, docs, CHANGELOG, release notes,
    install-hook) is generated from bench/results/latest.json, and CI
    checks each one against the row it comes from in the dated results file.
    It also rejects any percentage published outside a generated passage, and
    any balanced figure that does not name its testFixtures setting. This
    fixed stale figures: trufflehog in the README (an earlier full-dataset
    run), detect-secrets' leaky-repo extra lines, two CHANGELOG lines, and a
    triage figure that had no source row.
  • bench/breakdown.py: precision by confidence, path, context, detector
    family and policy, from the holdout report, with detection and blocking
    recall separately. Confidence is documented in the CLI help, the SARIF
    output (tool.driver.properties.confidenceScale) and docs/precision.md as
    a qualitative evidence level, not a probability.
  • Every provider-format rule (86) is tested at test, fixture, example and
    doc paths, .env.example and compose files: none is downgraded or stops
    blocking under balanced (TestNoProviderFormatDowngradedByLocation).
  • docs/benchmark-policy.md:
    labels used as given, a register of label disagreements (AWS WAF
    ChangeToken) reported only as a secondary figure, and a protocol for a
    second independent benchmark. The detection-code fingerprint is recorded
    with the figures, and a release fails if they were measured on different
    detection code. bench/score_labeled.py scores any line-labeled corpus.

Fixes from an external code review

  • Output files are never written through a link: reports, fix patches,
    hooks and --fix rewrites go to a new file in the destination directory
    that is renamed into place. A symlink at a report or patch path is refused
    (terminal and pipe links such as /dev/stdout still work), a symlinked
    hook is replaced by a regular file, --fix skips symlinked sources, and a
    failed report write leaves no partial file.
  • triage --max-report-megabytes N (default 256): a larger report, from a
    file or stdin, is rejected before parsing with exit 2.
  • triage enforces its 8 MiB source limit while reading: working-tree
    files are size-checked before reading and read through a capped reader;
    history blobs are size-checked with git cat-file -s and streamed with a
    cap, so a huge file named in a report can no longer exhaust memory.
  • --verify checks each secret once per run even under concurrency
    (in-flight requests are shared), and only a provider's documented success
    shape verifies (login for GitHub, object: balance for Stripe,
    data.viewer.id for Linear, ...): JSON error objects, empty documents and
    malformed bodies are unverified. 403 is no longer treated as verified.
    GitHub App installation tokens are checked against
    /installation/repositories.
  • README, docs and the install-hook message take their benchmark figures
    from bench/results/latest.json (bench/render_docs.py); CI fails if a
    published figure is stale.

Fixes from an adversarial recall and security review

  • One-word default passwords plus digits (admin@123, Welcome@2024,
    P@ssw0rd2023, Password1) under password keys are reported at low
    confidence outside test, example and doc files instead of being dropped
    as placeholders (still dropped there, ledger reason
    default-password-in-test-or-doc).
  • Local context no longer applies to Kubernetes service DNS
    (*.svc.cluster.local), other multi-label .local names
    (sql01.corp.local), .env.local / .env.*.local, or any path with a
    prod/production/prd/live segment.
  • redis://:password@host (empty user) is reported by url-credentials.
  • Placeholder phrases must be the whole value: mysecretkey_8f2kq and
    yourkey_<random> are reported.
  • Unquoted values in .env.*.*, .envrc, Makefiles, systemd units and
    .txt files are literals: random base64 there was dropped as
    operator-in-code about 40% of the time. Base64 starting with / or +
    is matched by generic-api-key.
  • Digit-free Bearer tokens (long, mixed case, high entropy) are reported;
    Authorization: <uuid> counts as a credential-named key.
  • --verify: only a JSON answer verifies (a proxy's HTML block or caution
    page no longer marks every secret live), and a 401 for GitHub/GitLab
    tokens is unverified, not invalid, because self-managed instances
    issue the same formats.
  • triage -f sarif keeps the source tool, triage status and commit, and a
    filtered value explains a reported finding only when it covers it.
  • --fix never rewrites a literal inside a comment, multi-line string or
    heredoc, Python bytes literals, or constant positions (PHP property and
    parameter defaults, C# case labels and optional parameters, Java
    constants used in case/annotations, TypeScript enums); Ruby, PHP and
    shell results are syntax-checked when the interpreter is installed.
  • Inputs skipped for --max-target-megabytes (files, stdin tail, diff
    additions) are reported in the summary instead of passing silently.

Changes since the first public commit, made in response to an external
review (benchmark rigor, default policy, filter safety, triage and --fix
safety, release hygiene):

Detection

  • Fixed: unquoted hex values (Key = acc993b3…) were classed as code
    identifiers and dropped, in scans and triage.
  • New rules for formats an independent benchmark (leaky-repo) showed were
    missed: unquoted passwords in env/INI/properties/YAML (password-in-config),
    WordPress/PHP define() secrets, Django SECRET_KEY, Laravel APP_KEY,
    XML password attributes and <Pass> elements, .netrc passwords, AWS key
    IDs in SigV4 credential scopes (Credential=AKIA…/20260101/…), and
    shadow, proftpdpasswd, Rails config/master.key and Firefox
    logins.json as sensitive files. pass is now a password key name.
  • Weak dictionary passwords (admin123) are reported at reduced confidence
    instead of being dropped; exact placeholder words are still filtered.
  • Fixed: SECRET_KEY=… was suppressed by the secret-reference name allowlist.
  • New noise filters, each with keep/reject/borderline tests: word tokens,
    values that repeat their own key name, string concatenation, e-mail
    addresses, and signature/auth scheme names (AWS4-HMAC-SHA256).

Policy and hooks

  • Git hooks (installed and pre-commit framework) default to the balanced
    policy; scans and CI still default to strict. install-hook prints the
    trade-off, and hooks explain every blocked finding.
  • Balanced now blocks high and medium confidence (before: high only) and
    lists weak evidence for review.
  • Generic values in test/example files block under balanced by default
    ...
Read more