Skip to main content

proofctl

A static-analysis linter and security scanner for the DevOps stack — Python, Terraform, Kubernetes, Helm, Dockerfiles, GitHub Actions, Shell — that catches the specific kinds of mistakes AI coding tools introduce. 271 rules, no external tools, runs in under a second.

proofctl check .
Rule Location Issue Severity
PROOFCTL-S-001 module/auth.py:42 SQL injection via string format in .execute() ERROR
PROOFCTL-Q-001 module/models.py:17 Mutable default argument — list assigned at def time ERROR
PROOFCTL-Q-002 module/loaders.py:88 Empty except Exception: swallows all errors silently WARNING
PROOFCTL-TF-A024 infra/sg.tf:14 SG rule 0.0.0.0/0 ingress on port 22 ERROR
PROOFCTL-YAML-022 k8s/deployment.yaml:8 Workload uses default namespace WARNING
PROOFCTL-YAML-007 .github/workflows/release.yml:23 Action not pinned to SHA ERROR
PROOFCTL-SECRET-001 infra/lambda.tf:8 AWS access key (AKIA...) ERROR

7 findings (4 ERROR, 3 WARNING) — exits non-zero (exit 2) so CI fails the build.


Why proofctl

LLM coding assistants ship code that compiles and looks correct but fails in predictable ways:

  • Insecure — SQL/command injection, hardcoded credentials, weak crypto, JWT signature bypass, public S3 buckets, K8s default namespaces.
  • Broken — hallucinated imports, type-hint vs implementation mismatch, pass-bodied functions shipped as real implementations.
  • Fragile — broad except Exception:, no timeouts, mutable defaults, defensive guards for impossible states, unused configuration kwargs.
  • Wasteful — single-method classes that should be functions, near-duplicate files, sprawling kwargs surface.

proofctl runs in pre-commit hooks, CI pipelines, or against an existing tree, catching these patterns before they merge. The top-firing rules on real AI-authored code are Q-002 broad except, Q-005 complexity, Q-006 long functions, YAML-007 / YAML-GHA-006 GitHub Actions hygiene, and YAML-GHA-003 missing permissions.


What proofctl scans

Language What it catches
Python Security (SQLi, injection, eval, JWT bypass, weak crypto), quality (mutable defaults, broad except, complexity, long functions), AI-slop patterns (echo docstrings, single-method classes, stale kwargs), import hallucinations
Terraform / HCL AWS / GCP / Azure resource hardening (200+ rules across IAM, encryption, public exposure, audit logs), AI-slop patterns (deprecated resources, AWS region in GCP, placeholder values), required_version, sensitive outputs
Kubernetes YAML Pod Security Standards (runAsNonRoot, allowPrivilegeEscalation, readOnlyRootFilesystem, drop ALL caps, seccomp), data-exfiltration vectors (default namespace, hostPath, low UID, RBAC wildcards, automountServiceAccountToken), image hygiene (latest tag, digest pinning)
Helm / Mustache Same K8s checks via Helm-templated YAML
Dockerfile USER, base image pinning, secret leakage, root-running, OCI labels, HEALTHCHECK, AI-generated antipatterns
GitHub Actions SHA-pinning, expression injection, missing permissions, missing timeouts, secret env-var leakage
Shell Common mistake detection (set -euo, dangerous globbing)
Secrets (any text file) AWS / GCP / GitHub / Slack / Stripe / private keys / JWTs / hardcoded passwords / K8s Secret YAML / HCL heredocs

Installation

pip install proofctl

Requires: Python 3.11+

No project dependencies are added — proofctl only scans, never imports your code.


Quick start

proofctl check .                          # scan current directory
proofctl check src/api/auth.py            # scan a single file
proofctl check . --min-severity ERROR     # only show ERROR
proofctl check . --fail-on ERROR          # CI gate: exit non-zero only on ERROR
proofctl check . --changed-only           # only files changed in this branch
proofctl check . --families S,Q,SECRET    # restrict rule families
proofctl check . --format html --output report.html
proofctl rules                            # list all rules

Pre-commit integration

Install proofctl from PyPI, then add a local hook in .pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: proofctl
        name: proofctl
        language: system
        entry: proofctl check
        args: [--no-pypi, --fail-on, ERROR]
        pass_filenames: false

CI integration (GitHub Actions)

name: proofctl
on: [push, pull_request]

jobs:
  proofctl:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install proofctl

      # --new-only compares against the committed baseline snapshot —
      # CI fails only on regressions introduced in this PR.
      - run: proofctl check . --no-pypi --fail-on ERROR --new-only

      - name: Generate HTML report
        if: failure()
        run: proofctl check . --no-pypi --format html --output proofctl-report.html || true

      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: proofctl-report
          path: proofctl-report.html
          retention-days: 14

Create a baseline snapshot for an existing project so CI only flags regressions:

proofctl baseline .
git add .proofctl-baseline.json
git commit -m "chore: add proofctl baseline"

Rules

271 rules across 13 families. Run proofctl rules after install to enumerate.

Family Count What it covers
Python — Quality (Q) 17 Mutable defaults, broad except, complexity, long functions, AI-slop patterns (echo docstrings, single-method classes, stale kwargs, defensive guards)
Python — Security (S) 24 OWASP Top-10 + CWE coverage: SQLi, command injection, weak crypto, JWT bypass, path traversal, XSS, SSRF, file upload, CSRF, missing authz, XPath injection, open redirect, TLS bypass
Secrets (SECRET) 13 AWS / GCP / GitHub / Slack / Stripe / private keys / JWTs / hardcoded passwords / K8s Secret YAML / connection strings with embedded creds
Python — Other 15 Placeholders, leakage (cross-language idioms, PII), import hallucination, variant detection, LLM guardrails (OWASP LLM Top-10)
Terraform — General + AI (TF-T, TF-AI) 25 required_version, sensitive outputs, IAM wildcards, mutable git refs, deprecated resources, AWS-region-in-GCP, placeholder values, image-family pinning, sensitive vars in VM metadata, unused variable declarations
Terraform — AWS (TF-A) 36 EC2 IMDSv2, S3 public-access-block, EBS encryption, VPC flow logs, KMS rotation, RDS hardening, SG / NACL / EKS / DynamoDB / ElastiCache / CloudTrail / IAM
Terraform — GCP (TF-G) 48 GKE hardening, GCS public-access prevention, IAM roles, KMS rotation, Cloud Function/Run public, BigQuery, Pub/Sub CMEK, Cloud SQL (TLS ssl_mode aware), firewall ingress, compute access scopes, Secret Manager CMEK consistency
Terraform — Azure (TF-AZ) 14 Storage public blob, SQL public network, AKS RBAC, Key Vault purge protection, NSG SSH/RDP, managed disk CMK
Terraform — Mechanics + Lifecycle (TF-M, TF-V) 10 SG inline mixing, force_destroy, mutable module refs, lifecycle antipatterns
Terragrunt (TG) 6 HCL inputs, mock_outputs, remote state encryption
Dockerfile (DF) 15 Latest tag, root user, secret leakage, OCI labels, HEALTHCHECK, legacy ENV form
Kubernetes YAML (YAML) 34 Pod Security Standards, hostPath, default namespace, image digest pinning, RBAC wildcards
GitHub Actions (YAML-GHA) 6 SHA pinning, expression injection, missing permissions, secret env-var leakage, missing timeouts
Shell (SH) 8 Dangerous globbing, missing set -euo pipefail
proofctl rules                 # full list
proofctl rules --family S      # filter by family
proofctl rules --severity ERROR

Suppressing findings

Inline (single line):

result = subprocess.run(cmd, shell=True)  # proofctl: ignore[PROOFCTL-S-002]
resource "aws_s3_bucket" "logs" {
  acl = "public-read"  # proofctl: ignore[PROOFCTL-TF-AI-003]  // or # comment style
}

Project-wide in .proofctl.yaml:

disable:
  - PROOFCTL-Q-004

Configuration

Place .proofctl.yaml in the project root:

exclude_paths:
  - "**/.venv/**"
  - "**/migrations/**"
  - "**/.terraform/**"

disable:
  - PROOFCTL-Q-004
  - PROOFCTL-DF-AI-002

severity_overrides:
  PROOFCTL-P-002: ERROR   # promote TODOs to ERROR

rules:
  PROOFCTL-P-002:
    allowed_formats:
      - 'TODO\(#\d+\)'    # allow TODO(#123) format
    exclude_paths:
      - tests/

  PROOFCTL-Q-003:
    any_threshold: 5

  PROOFCTL-V-002:
    similarity_threshold: 0.85
    min_file_lines: 30

  PROOFCTL-I-001:
    local_namespaces:
      - mycompany_
      - internal_

  PROOFCTL-TF-T013:
    required_labels:
      - environment
      - team
      - cost_center

# Substrings that mark a line as legitimate private infra. Findings from
# "name-shaped" rules (SECRET-*, TF-T005, TF-AI-001, DF-AI-*, Q-AI-*) on a
# line containing any of these tokens are silently dropped. Real
# code-shape security rules (S-001 SQLi, S-005 eval, etc.) keep firing.
internal_identifiers:
  - mycompany-prod         # internal hostname prefix
  - mycompany.internal     # internal DNS suffix
  - INTERNAL_PROJECT_NAME  # codename that sometimes looks like a placeholder

Commands

proofctl check

proofctl check [PATH] [OPTIONS]

Options:
  --format / -f        terminal | json | html           (default: terminal)
  --output / -o        Write report to file
  --changed-only       Only scan git-changed files
  --families           P,Q,S,L,I,V,LLM,TF,TG,DF,YAML,SH,SECRET
  --min-severity       INFO | WARNING | ERROR
  --fail-on            Exit non-zero at this severity (default: WARNING)
  --no-pypi            Skip PyPI lookups (faster, works offline)
  --new-only           Suppress findings present in .proofctl-baseline.json
  --fix                Auto-fix fixable findings (Q-001 mutable defaults)

proofctl baseline

Snapshot the current findings so future --new-only runs only surface regressions.

proofctl baseline .
git add .proofctl-baseline.json && git commit -m "chore: proofctl baseline"

proofctl rules

proofctl rules                 # list all
proofctl rules --family S      # filter by family
proofctl rules --severity ERROR

Exit codes

Code Meaning
0 No findings
1 Findings present, none at or above --fail-on threshold
2 One or more findings at or above --fail-on threshold

Output formats

Terminal (default) — rich-coloured table with file:line, rule, severity, hint.

JSON — machine-readable for CI:

{
  "schema_version": 1,
  "summary": { "total": 4, "ERROR": 3, "WARNING": 1 },
  "findings": [
    {
      "file": "module/auth.py",
      "line": 42,
      "col": 8,
      "rule_id": "PROOFCTL-S-001",
      "rule_name": "SQL injection",
      "severity": "ERROR",
      "message": "SQL injection via string format in .execute()",
      "hint": "Use parameterised queries: cursor.execute(sql, params)",
      "authority": "OWASP A03:2021, CWE-89"
    }
  ]
}

HTML — self-contained single-file dashboard with severity summary cards and a filterable table.


License

MIT

Metadata

Release files for proofctl 0.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for proofctl 0.6.1
File Size Uploaded
proofctl-0.6.1.tar.gz 174.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for proofctl 0.6.1
File Interpreter ABI Platform
proofctl-0.6.1-py3-none-any.whl Python 3 none any Details

Total release size: 360.2 kB

Release files / proofctl-0.6.1.tar.gz

Download URL proofctl-0.6.1.tar.gz
Size 174.8 kB
Tags Source
SHA-256 checksum
How to use checksums
8f5b875d962b9ab39cc30d6a9a89feeff19aea48aee4b76869cc9e4f532e48e4
BLAKE2b-256 checksum
How to use checksums
c3afd79b2e3cc03c7378ee26a8ea6bb5f1f0aa6197f8bf36131cb8e0deb646c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 24, 2026.

Transparency log

Release files / proofctl-0.6.1-py3-none-any.whl

Download URL proofctl-0.6.1-py3-none-any.whl
Size 185.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7cf01ba47e985cf3f716c810591e406730bce5ad4b8612740d9b1ed03cf33d08
BLAKE2b-256 checksum
How to use checksums
b08838fa9c93a8d2670c9050ba9a0b0c168862fb8e0636b69cef651c7cf9ae3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.6.1 This release

2 release files

0.6.0

2 release files

0.5.7

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page