Overview
scythe audit
scythe audit migrations/*.sql
scythe audit --format sarif -o audit.sarif

Exit codes: 0 (no errors, or --exit-zero), 1 (configuration error), 2 (error-severity findings).

Rule catalog#

Security (SC-SEC*, 12 rules)#

ID Name Severity Coverage
SC-SEC01 dangerous-function error Filesystem, network, shell access (CWE-78)
SC-SEC02 grant-all error GRANT ALL privilege widening (CWE-269)
SC-SEC03 grant-to-public error GRANT … TO PUBLIC (CWE-269)
SC-SEC04 superuser-role error High-privilege role attributes — Postgres only (CWE-269)
SC-SEC05 literal-password error Hard-coded passwords in role creation — Postgres only (CWE-798)
SC-SEC06 weak-hash-in-auth error md5()/sha1() over credentials (CWE-327, CWE-916)
SC-SEC07 select-star-pii warn SELECT * with PII/credential columns (CWE-200)
SC-SEC08 cartesian-join error Unconstrained joins (CWE-400)
SC-SEC09 unbounded-like warn LIKE '%…%' patterns (CWE-1333)
SC-SEC10 security-definer-no-search-path error Missing pinned search_path — Postgres only (CWE-426)
SC-SEC11 session-mutation error SET ROLE/SET SESSION AUTHORIZATION/RESET ROLE — Postgres only (CWE-269)
SC-SEC12 function-search-path-mutable warn CREATE FUNCTION without explicit SET search_path — Postgres only (CWE-426)

Row Level Security (SC-RLS*, 3 rules, Postgres-only)#

ID Name Severity Coverage
SC-RLS01 policy-references-user-metadata error Editable JWT claims instead of app_metadata (CWE-639)
SC-RLS02 policy-always-permissive error Permissive RLS policy with an always-true condition (CWE-285)
SC-RLS03 policy-uses-uncached-auth-function warn Direct calls to auth.uid()/auth.jwt()/current_setting() (CWE-405)

Migration Safety (SC-MIG*, 19 rules, Postgres-only)#

ID Name Severity Coverage
SC-MIG01 ban-drop-table error DROP TABLE — irreversible
SC-MIG02 ban-drop-column error ALTER TABLE … DROP COLUMN — breaks deployed readers
SC-MIG03 require-concurrent-index-creation error CREATE INDEX without CONCURRENTLYACCESS EXCLUSIVE lock
SC-MIG04 renaming-column error ALTER TABLE … RENAME COLUMN — breaks deployed readers
SC-MIG05 constraint-missing-not-valid error ADD CONSTRAINT without NOT VALID — validates all rows
SC-MIG06 ban-drop-database-or-schema error DROP DATABASE/DROP SCHEMA — irreversible
SC-MIG07 renaming-table error ALTER TABLE … RENAME TO — breaks deployed readers
SC-MIG08 ban-truncate-cascade error TRUNCATE … CASCADE — clears referencing tables
SC-MIG09 ban-alter-column-type error ALTER COLUMN … TYPE — full table rewrite
SC-MIG10 prefer-bigint-over-int error 32-bit integer types — overflow risk
SC-MIG11 prefer-text-over-varchar error Variable-length strings — length increases block writes
SC-MIG12 prefer-timestamptz error timestamp without time zone — session timezone issues
SC-MIG13 prefer-identity-over-serial error serial/bigserial/smallserial types
SC-MIG14 disallowed-unique-constraint error ADD CONSTRAINT … UNIQUE — inline index building
SC-MIG15 adding-primary-key-constraint error ADD CONSTRAINT … PRIMARY KEY — inline index building
SC-MIG16 ban-create-domain-with-constraint error CREATE DOMAIN with CHECK — validates all rows
SC-MIG17 ban-drop-not-null error ALTER COLUMN … DROP NOT NULL — relaxes deployed contracts
SC-MIG18 adding-not-nullable-field warn ADD COLUMN … NOT NULL without DEFAULT
SC-MIG19 unsupported-reg-types error reg* OID columns — pg_upgrade incompatibility

Antipattern (SC-CHK01, 1 rule)#

ID Name Severity Coverage
SC-CHK01 check-constraint-always-true warn Tautological CHECK constraints — Postgres only

Suppression#

-- scythe-audit: ignore[SC-SEC02] reason="security-reviewed: vetted role"
GRANT ALL ON internal_audit TO ops_admin;

Suppress multiple rules with ignore[SC-SEC01,SC-SEC02]. Run without any suppressions honored using --ignore-suppressions.

Severity filtering and exit codes#

Desired outcome Flags
Errors only --severity error
Warnings, no build failure --exit-zero
Block on errors (default) (none)
Advisory mode --severity warn --exit-zero

User-defined rules#

Custom rule IDs must start with USER- and are declared under [audit] or extra_rules in scythe.toml — see Configuration for the full block syntax and 28 available matchers (function_name_in_set, grant_kind, cartesian_join, drop_statement, and more).

CI integration#

GitHub Actions — SARIF upload:

- name: Run scythe audit
  run: scythe audit --format sarif -o audit.sarif --exit-zero
- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: audit.sarif

GitLab CI — SAST report:

audit:
  image: rust:latest
  script:
    - cargo install scythe-cli
    - scythe audit --format json -o gl-sast-report.json --exit-zero
  artifacts:
    reports:
      sast: gl-sast-report.json

Pre-commit — block on errors:

- repo: https://github.com/Goldziher/scythe
  rev: v0.15.0
  hooks:
    - id: scythe-audit

By default scythe audit exits with code 2 on error findings, which pre-commit treats as a hook failure. Add --exit-zero for advisory-only integration.

Updated

Was this page helpful?