Like a linter, but for CI/CD and DevOps mistakes
PipeGuard is a lightweight Python CLI that scans your repository for risky CI/CD workflows, insecure Dockerfiles, and common DevOps configuration mistakes
It helps catch issues such as:
- Unpinned GitHub Actions
- Over-permissive workflow tokens
- Unsafe
pull_request_targetusage - Dangerous
curl | bashcommands - Docker images running as root
- Dockerfiles using
latesttags - Missing Docker healthchecks
- Committed
.envfiles - Committed tokens and private keys
- Unpinned Python dependencies
- Python packages with known vulnerabilities from
pip-audit - Docker OS packages that cannot be reliably image-audited
Install from PyPI:
pip install pipeguard-scanner-cliThe installed command is pipeguard
For local development, install from the project directory with development tools:
pip install -e ".[dev]"Scan the current repository:
pipeguard scan .Scan a specific repository:
pipeguard scan /path/to/projectScan a public Git repository:
pipeguard scan https://github.com/owner/repo --ref main| Command | Purpose |
|---|---|
pipeguard --version |
Show the installed PipeGuard version |
pipeguard scan . |
Scan the current directory |
pipeguard scan <path> |
Scan a specific project folder |
pipeguard scan https://github.com/owner/repo |
Clone and scan a public Git repository in a temporary directory |
pipeguard scan <path> --category cicd |
Scan only GitHub Actions workflows |
pipeguard scan <path> --category docker |
Scan only Dockerfiles |
pipeguard scan <path> --category iac |
Scan Docker Compose and Kubernetes manifests |
pipeguard scan <path> --category repo |
Scan only repository health checks |
pipeguard scan <path> --category secrets |
Scan only committed secret patterns |
pipeguard scan <path> --category vuln |
Scan dependency and Docker package audit readiness |
pipeguard scan <path> --exclude "dist/**" |
Exclude paths from scanning and reporting |
pipeguard scan <path> --docker-image image:tag |
Scan a Docker image with Trivy or Grype, bootstrapped automatically when missing |
pipeguard scan <path> --image-scanner trivy |
Select the Docker image vulnerability scanner |
pipeguard scan <path> --output report.md |
Export a Markdown report |
pipeguard scan <path> --output report.json |
Export a JSON report |
pipeguard scan <path> --output report.sarif |
Export a SARIF report for code scanning |
pipeguard scan <path> --fail-on high |
Exit with code 1 when high or critical findings exist |
pipeguard scan <path> --ignore RULE_ID |
Ignore a specific rule ID |
pipeguard scan <path> --config pipeguard.yml |
Load a specific PipeGuard config file |
Scan only GitHub Actions workflows:
pipeguard scan . --category cicdScan only Dockerfiles:
pipeguard scan . --category dockerScan only Docker Compose and Kubernetes manifests:
pipeguard scan . --category iacScan only repository health checks:
pipeguard scan . --category repoScan only committed secret patterns:
pipeguard scan . --category secretsScan only Python package vulnerabilities and Docker package audit readiness:
pipeguard scan . --category vulnScan a Docker image with an installed scanner:
pipeguard scan . --category vuln --docker-image python:3.12 --image-scanner autoWhen --docker-image is used, PipeGuard first looks for an installed Trivy or Grype binary.
If neither is available, it downloads the official scanner installer into a temporary tools
directory, runs the scan, and deletes the temporary directory afterward.
PipeGuard prints tracking logs, a progress bar, a summary panel, and findings grouped by severity. The examples below are abbreviated from real category scans.
GitHub Actions:
track Scanning GitHub Actions workflows
track Scan complete
Scan complete ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
PipeGuard Scan Report
Scanned path: /path/to/your-project
Findings: 9 | Critical: 0 | High: 2 | Medium: 7 | Low: 0
HIGH
GH_ACTION_JOB_WRITE_PERMISSION cicd .github/workflows/release-tag.yml 24 Job grants write token permissions
GH_ACTION_SECRET_IN_PULL_REQUEST cicd .github/workflows/python-security.yml 120 Workflow references secrets in pull request context
MEDIUM
GH_ACTION_UNPINNED_ACTION cicd .github/workflows/aws.yml 22 GitHub Action is not pinned to a commit SHA
GH_ACTION_WORKFLOW_WRITE_PERMISSION cicd .github/workflows/tag-codebuild-gated.yml 33 Workflow grants write token permissions
Docker:
track Scanning Dockerfiles
track Scan complete
Scan complete ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
PipeGuard Scan Report
Scanned path: /path/to/your-project
Findings: 3 | Critical: 0 | High: 0 | Medium: 2 | Low: 1
MEDIUM
DOCKER_LATEST_TAG docker side-jobs/delete-junk-provider-redis-queue/Dockerfile 1 Docker image uses latest or implicit latest tag
DOCKER_RUNNING_AS_ROOT docker side-jobs/delete-junk-provider-redis-queue/Dockerfile - Dockerfile does not switch to a non-root user
LOW
DOCKER_MISSING_HEALTHCHECK docker side-jobs/delete-junk-provider-redis-queue/Dockerfile - Dockerfile does not define a healthcheck
Repository health:
track Scanning repository health
track Scan complete
Scan complete ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
PipeGuard Scan Report
Scanned path: /path/to/your-project
Findings: 31 | Critical: 0 | High: 0 | Medium: 0 | Low: 31
LOW
REPO_LARGE_FILE repo swagger-codegen/swagger-codegen-cli.jar - Large file found in repository
REPO_MISSING_ENV_EXAMPLE repo . - Repository is missing .env.example
REPO_REQUIREMENTS_UNPINNED repo requirements.txt 2 Python dependency is not fully pinned
Secrets:
track Scanning committed secret patterns
track Scan complete
Scan complete ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
PipeGuard Scan Report
Scanned path: /path/to/your-project
Findings: 61 | Critical: 61 | High: 0 | Medium: 0 | Low: 0
CRITICAL
SECRET_AWS_ACCESS_KEY secrets app/config.py 25 AWS access key appears to be committed
SECRET_PRIVATE_KEY secrets certs/badkey.pem 1 Private key appears to be committed
Vulnerability scan:
track Scanning dependency vulnerabilities
track Collecting Python dependency manifests
track Preparing isolated pip-audit virtual environments
track Virtualenv isolation unavailable, using temporary target directories
track Installing pip-audit into temporary tools directory
track Installing target dependencies from requirements.txt
track Running pip-audit against temporary target directory
track Parsing pip-audit advisory results
track Checking Dockerfile package installs
track Scan complete
Scan complete ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
PipeGuard Scan Report
Scanned path: /path/to/your-project
Findings: 28 | Critical: 0 | High: 28 | Medium: 0 | Low: 0
HIGH
VULN_PYTHON_PACKAGE_VULNERABLE vuln requirements.txt 18 Python package has known vulnerability CVE-2024-37891
VULN_PYTHON_PACKAGE_VULNERABLE vuln requirements.txt 28 Python package has known vulnerability CVE-2025-68616
Docker image vulnerability scan:
track Scanning Docker image python:3.9-slim
track Scan complete
Scan complete ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
PipeGuard Scan Report
Scanned path: /path/to/your-project
Findings: 199 | Critical: 6 | High: 44 | Medium: 85 | Low: 64
CRITICAL
VULN_DOCKER_IMAGE_PACKAGE_VULNERABLE vuln python:3.9-slim - Docker image package has known vulnerability CVE-2025-15467
HIGH
VULN_DOCKER_IMAGE_PACKAGE_VULNERABLE vuln python:3.9-slim - Docker image package has known vulnerability CVE-2026-0861
All checks:
track Scanning GitHub Actions workflows
track Scanning Dockerfiles
track Scanning repository health
track Scanning committed secret patterns
track Scanning dependency vulnerabilities
track Scan complete
Scan complete ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
PipeGuard Scan Report
Scanned path: /path/to/your-project
Findings: 132 | Critical: 61 | High: 30 | Medium: 9 | Low: 32
Export a Markdown report:
pipeguard scan . --output report.mdExport JSON:
pipeguard scan . --output report.jsonExport JSON for another project:
pipeguard scan /path/to/flask-app --output flask-app-pipeguard.jsonExport SARIF for code scanning:
pipeguard scan . --output pipeguard.sarifScan the bundled unsafe example project:
pipeguard scan examplesExport the bundled unsafe example project to JSON:
pipeguard scan examples --output examples-pipeguard.jsonScan slynk-api:
pipeguard scan /path/to/slynk-apiExport slynk-api to JSON:
pipeguard scan /path/to/slynk-api --output slynk-api-pipeguard.jsonScan Syncraft:
pipeguard scan /path/to/SyncraftExport Syncraft to JSON:
pipeguard scan /path/to/Syncraft --output syncraft-pipeguard.jsonFail CI when high-risk issues are found:
pipeguard scan . --fail-on highIgnore a specific rule:
pipeguard scan . --ignore GH_ACTION_UNPINNED_ACTIONYou can also create pipeguard.yml in the repository root:
ignore:
- GH_ACTION_UNPINNED_ACTION
exclude:
- examples/**
- tests/fixtures/**
- .security-target/**
- .security-tools/**
fail_on: high
rules:
DOCKER_MISSING_HEALTHCHECK:
severity: medium
REPO_MISSING_ENV_EXAMPLE: offPipeGuard also looks for pipeguard.yaml, .pipeguard.yml, and .pipeguard.yaml
Use --config path/to/file.yml to load a specific config file
See RULES.md for rule IDs, severities, and fixes.
| Rule | Severity | Description |
|---|---|---|
GH_ACTION_UNPINNED_ACTION |
Medium | Action is pinned to a tag or branch instead of a full SHA |
GH_ACTION_MISSING_PERMISSIONS |
Medium | Workflow does not define least-privilege permissions |
GH_ACTION_WORKFLOW_WRITE_PERMISSION |
Medium | Workflow grants at least one write token permission |
GH_ACTION_WRITE_ALL_PERMISSION |
High | Workflow grants write-all token permissions |
GH_ACTION_JOB_WRITE_PERMISSION |
High | Job grants at least one write token permission |
GH_ACTION_PULL_REQUEST_TARGET |
High | Workflow uses pull_request_target |
GH_ACTION_PULL_REQUEST_TARGET_CHECKOUT_HEAD |
Critical | Workflow appears to use PR head code with pull_request_target |
GH_ACTION_SECRET_IN_PULL_REQUEST |
High | Workflow references secrets in pull request context |
GH_ACTION_WORKFLOW_RUN_TRIGGER |
Medium | Workflow uses workflow_run trigger |
GH_ACTION_CHECKOUT_PERSIST_CREDENTIALS |
Medium | Checkout persists GitHub credentials |
GH_ACTION_CURL_BASH |
High | Workflow pipes remote script directly into shell |
GH_ACTION_PIP_INSTALL_REMOTE_URL |
Medium | Workflow installs Python package from a remote URL |
GH_ACTION_DOCKER_LOGIN_PASSWORD |
Medium | Workflow performs Docker login with a password/secret |
GH_ACTION_PYPI_TOKEN_PUBLISH |
Medium | Workflow appears to use a long-lived PyPI token |
| Rule | Severity | Description |
|---|---|---|
DOCKER_LATEST_TAG |
Medium | Base image uses latest or implicit latest tag |
DOCKER_RUNNING_AS_ROOT |
Medium | Dockerfile does not switch to non-root user |
DOCKER_MISSING_HEALTHCHECK |
Low | Dockerfile does not define a healthcheck |
DOCKER_APT_NO_CLEANUP |
Low | apt package lists are not cleaned |
DOCKER_COPY_ENTIRE_CONTEXT |
Low | Dockerfile copies the whole context |
DOCKER_SECRET_ENV |
Critical | Dockerfile contains a likely secret in ARG/ENV |
| Rule | Severity | Description |
|---|---|---|
COMPOSE_PRIVILEGED_SERVICE |
High | Compose service runs with privileged mode |
COMPOSE_HOST_NETWORK |
Medium | Compose service uses host networking |
COMPOSE_RUNS_AS_ROOT |
Medium | Compose service runs as root |
K8S_PRIVILEGED_CONTAINER |
High | Kubernetes container runs privileged |
K8S_HOST_PATH_VOLUME |
High | Kubernetes workload mounts a hostPath volume |
K8S_CONTAINER_RUNS_AS_ROOT |
Medium | Kubernetes container runs as UID 0 |
K8S_MISSING_RESOURCE_LIMITS |
Low | Kubernetes container is missing resource limits |
| Rule | Severity | Description |
|---|---|---|
REPO_MISSING_README |
Low | Repository is missing a README |
REPO_MISSING_GITIGNORE |
Low | Repository is missing .gitignore |
REPO_ENV_FILE_COMMITTED |
Critical | .env style file appears committed |
REPO_MISSING_ENV_EXAMPLE |
Low | Repository is missing .env.example |
REPO_REQUIREMENTS_UNPINNED |
Low | Python dependency is not fully pinned |
REPO_MISSING_PYPROJECT |
Low | Python project may lack modern packaging config |
REPO_LARGE_FILE |
Low | Large file found in repository |
| Rule | Severity | Description |
|---|---|---|
VULN_PYTHON_PACKAGE_VULNERABLE |
High | pip-audit reported a known vulnerability for a pinned Python package |
VULN_PIP_AUDIT_UNAVAILABLE |
Medium | Isolated pip-audit environment setup or execution failed |
VULN_DOCKER_OS_PACKAGE_UNPINNED |
Medium | Dockerfile installs an OS package without an exact version |
VULN_DOCKER_IMAGE_PACKAGE_VULNERABLE |
Low-Critical | Trivy or Grype reported a vulnerable package in a Docker image |
VULN_DOCKER_IMAGE_SCANNER_UNAVAILABLE |
Medium | Docker image scan was requested but Trivy or Grype could not be found or bootstrapped |
| Rule | Severity | Description |
|---|---|---|
SECRET_PRIVATE_KEY |
Critical | Private key appears to be committed |
SECRET_GITHUB_TOKEN |
Critical | GitHub token appears to be committed |
SECRET_AWS_ACCESS_KEY |
Critical | AWS access key appears to be committed |
SECRET_STRIPE_KEY |
Critical | Stripe live secret key appears to be committed |
SECRET_SLACK_TOKEN |
High | Slack token appears to be committed |
SECRET_JWT_TOKEN |
Medium | JWT appears to be committed |
Most teams review application code carefully, but CI/CD workflows, Dockerfiles, and repository setup often receive less attention
PipeGuard gives your repository a quick DevOps health check before small configuration mistakes become production or supply-chain problems
Run tests:
pytestRun linting:
ruff check .PipeGuard is released under the MIT License
Copyright (c) 2026 Liem Tran