← Back to PullGuard

Getting Started

Add PullGuard to a GitHub repository in under five minutes. Three install paths โ€” pick the one that matches your team size and procurement process.

What PullGuard scans

46 analyzers grouped into six capability categories. Every category produces findings with severity, file:line location, remediation guidance, and (where relevant) a dollar-cost estimate. Free tier runs 14 of the 46; paid tiers unlock the rest.

๐Ÿ”’ Security (15 OWASP checks + supply-chain)

SQL / XSS / SSRF / command / path injection, AI application security (OWASP LLM & Agentic Top-10, across hosted, private & self-hosted models), deserialisation, CORS / CSP misconfigurations, missing CSRF, JWT confusion, cookie security, HTTP security headers, SSTI, unsafe reflection, file-upload validation, cryptographic hygiene, generic injection sinks. Cross-file, inter-procedural taint tracking across seven languages (JS / TS, Python, Java, C#, Go, Rust).

๐Ÿ“Š Code quality

Cyclomatic and cognitive complexity, Type-1โ€“3 clone detection, dead code and unused exports, monolithic-file detection (NCLOC-aligned โ€” heavily-documented code is not penalised), deep nesting, naming conventions, file naming, error-handling patterns, test patterns, API consistency.

๐Ÿ—๏ธ Architecture

Layer violations (e.g., domain code calling presentation), circular dependencies, transitive cycle detection across the full module graph, type-coverage gaps in TypeScript, OpenAPI contract drift between code and spec, module-system inconsistencies, knowledge-silo files (single-contributor risk).

๐Ÿ“ฆ Supply chain

Dependency CVEs across five ecosystems (npm, PyPI, Maven / Gradle, Go, RubyGems) using the OSV database โ€” works air-gapped against a local mirror โ€” with EPSS exploit-probability + CISA KEV “actively exploited” prioritisation so the vulnerabilities attackers actually target rise to the top. Dependency freshness scoring, breaking-change detection on shared interfaces, dangerous-files detection (tracked secrets, private keys, credentials), git-history secret scanning across the last 100 commits.

๐Ÿค– AI & modern dev

AI × security composite (code carrying an AI-era risk signal alongside a real security flaw becomes one prioritised “human-review” finding instead of separate noise), AI-governance evidence (explicit AI-authorship provenance markers, as advisory evidence toward EU AI Act / NIST AI RMF โ€” evidence toward, never a grant), AI-era risk detection (hallucinated dependencies, secrets-to-LLM prompts, insecure-by-default snippets), per-PR cost-of-change estimation in dollars, breaking-change blast-radius analysis with caller counts, GitHub Actions workflow security (unpinned actions, pwn-request, script injection, token over-permissions), Dockerfile misconfigurations, Kubernetes IaC checks (CIS Level 1 baseline).

๐Ÿ“‹ Compliance evidence

SOC 2 (8 controls โ€” CC3.1, CC3.3, CC4.1, CC6.1, CC6.2, CC6.7, CC6.8, CC8.1), HIPAA Technical Safeguards (45 CFR ยง164.312), PCI DSS 4.0, NIST 800-53 Rev 5, ISO 27001:2022. Each control is mapped to the analyzers that produce evidence; reports show PASS / CONCERN / FAIL per control with violation counts and AICPA / NIST citation text. Three AI-era frameworks โ€” EU AI Act, ISO/IEC 42001, NIST AI RMF โ€” are separate opt-ins, off by default, each framed as evidence supporting an obligation, never a compliance verdict.

Language support — what “supported” means per language

“Supported” is not one thing. Some languages get full taint-flow analysis: PullGuard traces attacker-controlled input from where it enters your code to where it reaches a dangerous sink — across functions and across files — and reports only when it can follow the path. Others get pattern rules: calibrated matches on risky shapes, which find real issues but do not prove a flow. Dependency CVE scanning is separate again and follows the package manifest, not the language. This table is the honest split, and a test asserts it against the shipped catalogs so it cannot drift from the product.

Language Extensions Taint-flow analysis Pattern & secret rules Dependency CVEs
JavaScript / TypeScript.js .jsx .mjs .cjs .ts .tsx .mts .cts✓ Taint-flow✓npm
Python.py✓ Taint-flow✓PyPI
Java.java✓ Taint-flow✓Maven / Gradle
C#.cs✓ Taint-flow✓—
Go.go✓ Taint-flow✓Go
Rust.rs✓ Taint-flow✓—
PHP.php— Pattern rules only✓—
Ruby.rb— Pattern rules only✓RubyGems

Everything else — Kotlin, Swift, C / C++, Bash, Terraform, YAML, Dockerfiles and the rest of the language registry — is covered by the quality, architecture, secret-scanning, IaC and workflow-security analyzers, plus any pattern rules that apply, but not by taint-flow analysis.

Ruby, specifically. Ruby files are parsed and scanned by the secret, quality, architecture and compliance analyzers, and RubyGems dependencies are checked against the CVE database — but there is no Ruby taint-flow analysis. A Ruby SQL injection that dataflow would catch in Java or Python is not caught here. We would rather say that than let “Ruby is supported” imply a depth we do not ship. PHP is the same shape for a different reason: the parser and sink catalogs exist, but PHP taint stays disabled until a known false-positive class is resolved — we do not ship a rule we know over-fires.

Install

Three paths โ€” same scanner image, same workflow file, different license tier.

Free

14 analyzers ยท no signup ยท no payment

Every public and private GitHub repository can run the free tier without an account or license key. You get the 12 commodity SAST / quality checks plus the supply-chain "dangerous files" and "repo hygiene" analyzers.

1. Drop this workflow file at .github/workflows/pullguard.yml:

name: PullGuard

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

permissions:
  contents: read
  pull-requests: write
  checks: write

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0          # Required for git-history analyzers

      - uses: pullguard-dev/pullguard-action@v1

2. Open a pull request.

PullGuard runs on every PR push, posts a comment with findings, writes a Step Summary to the Actions tab, and uploads the JSON / Markdown report as a workflow artifact.

Pro Team

44 / 46 analyzers ยท Stripe checkout ยท live in <5 min

Pro unlocks 44 of 46 analyzers for one private repository โ€” the full deep-analysis catalogue except enterprise custom rules. Team adds custom rules + up to 10 private repositories with unlimited contributors. Both bind to your organisation/repo at first scan; re-binding requires a support email.

1. Buy at pullguard.dev/#pricing via Stripe checkout.

Pro is $29/month, Team is $99/month. Stripe handles billing, invoicing, and tax. Cancel from your Stripe customer portal.

2. Receive your pg_live_* license token by email (instant).

3. Add the token as a repository secret named PULLGUARD_LICENSE_KEY:

GitHub repo โ†’ Settings โ†’ Secrets and variables โ†’ Actions โ†’ New repository secret. Or for organisation-wide use: Settings โ†’ Secrets at the org level.

4. Reference it in your workflow:

      - uses: pullguard-dev/pullguard-action@v1
        with:
          license-key: ${{ secrets.PULLGUARD_LICENSE_KEY }}

On the next PR scan, 44 of 46 analyzers run, multi-framework compliance evidence appears, and the cost-estimation dollar amounts populate.

5. Dependency CVEs: the database ships in the image

Every published scanner image carries a vulnerability database refreshed when the image was built, so CVE lookups run locally, deterministically and offline with no configuration — in the Action and from docker run alike. A runner that cannot reach the advisory service still reports every CVE. When the image's data is older than db.maxAgeDays (default 7) and the network is reachable, the scan also consults the advisory service and merges the result; it never replaces the local data with an empty answer. A run whose lookup could not complete says INCOMPLETE on the console and in the report (--fail-on-incomplete makes it exit non-zero).

pullguard db status          # which database this scan will open, and how old it is
pullguard db update          # CLI installs: download or refresh your own copy

To use a fresher database than the image's, mount one and point db.path (or PULLGUARD_DB_PATH) at it. Full options under Air-gapped mode.

Enterprise

All 46 analyzers ยท Marketplace App ยท annual contract

Enterprise adds the GitHub Marketplace pullguard-code-scanner App (which provisions the workflow file automatically), native Check Run annotations on the PR Files-changed view, a 4 business-hour response SLA, and an annual contract with a master service agreement and data-processing addendum. SSO (SAML / OIDC), RBAC, and a hash-chained, admin-exportable audit trail are included; out-of-database tamper-proof audit anchoring is on the roadmap.

1. Contact sales:

hello@pullguard.dev โ€” book a 30-minute call. We'll discuss repo count, contributor count, compliance frameworks in scope, and procurement requirements.

2. Install the GitHub App:

After contract signature, install pullguard-code-scanner on your GitHub organisation. The App auto-opens a provisioning pull request with the four-line workflow file ready to merge.

3. Enable native Check Run rendering:

      - uses: pullguard-dev/pullguard-action@v1
        with:
          license-key: ${{ secrets.PULLGUARD_LICENSE_KEY }}
          report-to-app: true

With report-to-app: true the PR-comment + Step-Summary surfaces continue to work AND findings appear as native Check Run annotations on the Files-changed view (line-level red flags, inline severity badges).

Your first scan

On the next pull request after install, four customer-visible surfaces light up:

PR comment

A comment posted on the pull request showing grade, score, severity breakdown, top 10 actionable findings inline, expandable <details> sections for Cost Breakdown / Health Dashboard / SOC 2 Evidence / Security Findings / AI Usage Enterprise / Quick Wins, and a footer link back to the workflow run for the full report.

Actions tab โ†’ Step Summary

The richer view: full Health Dashboard with per-category grade and cost, Top Risks table sorted by remediation cost, Security Findings callout, all 8 SOC 2 controls with PASS / CONCERN / FAIL, plus HIPAA / PCI / NIST / ISO 27001 evidence sections.

Workflow artifact

pullguard-report.json + pullguard-report.md uploaded to the workflow run, retained 30 days, downloadable for programmatic ingestion or audit archive.

Native Check Runs (Enterprise + Marketplace App)

With report-to-app: true findings appear as inline annotations on the Files-changed view of the pull request โ€” clickable red / orange / yellow flags with severity, file:line, and remediation guidance. Same data the PR comment shows; native GitHub UX. Setup: install the PullGuard App on the repository and use an online (pg_live_…) license key.

Customising the scan

Two configuration surfaces. Both are optional โ€” PullGuard works out of the box.

Full reference at Configuration โ†’.

What the output actually looks like

Before you install anything: open the live scan on our public playground repo → — a real pull request, scanned by the released Action, with the PullGuard comment and Check Run on it. Every vulnerability in that repo was planted deliberately, so every finding on the PR is a true positive.

Below is a real PR comment, abridged — it is the output of the shipped formatter on a two-file service with one SQL injection and one command injection. Nothing here is mocked up.

## ๐Ÿ”ด PullGuard Report

โŒ **Gate: FAIL โ€” 2 blocking critical findings (policy: fail the build on any
critical-severity finding)**

**Score: 79/100** (Grade ๐Ÿ”ด F) ยท 5 findings across 3 files

<details>
<summary><strong>Severity Breakdown</strong></summary>

| Severity    | Count |
|-------------|-------|
| ๐Ÿ”ด critical | 2     |
| ๐ŸŸ  major    | 1     |
| ๐Ÿ”ต minor    | 2     |

</details>

<details>
<summary><strong>๐Ÿ“‹ SOC 2 Security Evidence</strong></summary>

**Security Posture:** 6/8 controls in good standing (1 monitoring-only),
0 concerns, 2 failures.

| Control                          | Status         | Findings |
|----------------------------------|----------------|----------|
| CC3.1 Risk Assessment            | โŒ FAIL        | 2        |
| CC6.1 Logical Access Controls    | โŒ FAIL        | 2        |
| CC6.2 Authentication / User IDs  | โœ… PASS        | 0        |
| CC6.7 Cryptographic Controls     | โœ… PASS        | 0        |

</details>

<details>
<summary><strong>๐Ÿ”’ Security Findings (2)</strong></summary>

| Severity    | Rule                        | File:Line       | Description                                                                | Effort |
|-------------|-----------------------------|-----------------|----------------------------------------------------------------------------|--------|
| ๐Ÿ”ด critical | `builtin/security-patterns` | `src/db.js:2`     | Potential SQL injection in src/db.js: user input concatenated into SQL query | medium |
| ๐Ÿ”ด critical | `builtin/security-patterns` | `src/refund.js:3` | Potential command injection in src/refund.js: user input passed to shell command | low |

</details>

### Top Findings

| Severity    | Rule                        | File:Line         | Description                                                | Effort  |
|-------------|-----------------------------|-------------------|------------------------------------------------------------|---------|
| ๐Ÿ”ด critical | `builtin/security-patterns` | `src/db.js:2`     | Potential SQL injection โ€ฆ                                    | medium  |
| ๐Ÿ”ด critical | `builtin/security-patterns` | `src/refund.js:3` | Potential command injection โ€ฆ                                | low     |
| ๐ŸŸ  major    | `builtin/repo-hygiene`      | `<repo-root>`     | Missing CI workflows (.github/workflows/).                   | low     |
| ๐Ÿ”ต minor    | `builtin/dead-code`         | `src/db.js:1`     | Orphaned file: src/db.js is not imported by any other file.  | trivial |

<details>
<summary>๐Ÿงฐ Triage โ€” fingerprints for <code>/pullguard ignore</code> (5)</summary>

Comment `/pullguard ignore <fingerprint> for:30d <reason>` on this PR (repo
collaborators only) to add a reviewed, TIME-BOXED `.pullguardignore` entry โ€” it
reverts automatically and the finding comes back.

| Finding                     | File              | Triage                                            |
|-----------------------------|-------------------|---------------------------------------------------|
| `builtin/security-patterns` | `src/db.js`       | `1egz27g_126` โ€” always-surfaced; acknowledge or a  |
|                             |                   | reasoned `false_positive` override (stays visible) |
| `builtin/repo-hygiene`      | `<repo-root>`     | `/pullguard ignore emzfz0_153 for:30d <reason>`     |

</details>

The full comment also carries the cost estimate, the health dashboard, quick wins, and — if you use them — the compliance strip and the suppression state. Security findings are always surfaced: they appear on the PR comment, the Step Summary, the JSON report, the SARIF output and the gate, and no suppression can silently remove them.

View your results

Your first 30 days

Most of what a team gets from PullGuard comes from a few switches beyond the first scan. pullguard doctor . lists which of them your repository already uses and links the rest.

  1. Week 1 — commit a baseline on your base branch (pullguard scan --update-baseline), so pull requests report only what they introduce. Baselines →
  2. Week 1 — upload SARIF so findings appear in the code-scanning tab and in your IDE. SARIF →
  3. Week 2 — triage with reviewed suppressions in .pullguardignore: time-boxed, reason required, and security findings stay visible. Suppressions →
  4. Week 3 — set SLA budgets and ownership so aged findings are flagged and the list routes itself to the people who own the code. SLA → · Ownership →
  5. Week 4 — turn on what your auditors ask for: the compliance frameworks you report against, and test coverage with a minimum for new code. Compliance → · Coverage →

๐Ÿ” Code never leaves your runners

The PullGuard scanner is a Docker image (ghcr.io/pullguard-dev/pullguard) that runs as a container on your own GitHub Actions runners. By default the action pins the stable :1 release line (newest v1.x); set the image-pin input to latest, a release tag, or a digest to change it. Source code is analyzed locally; only license validation (Stripe-issued pg_live_* tokens) and dependency-vulnerability lookups (OSV API) make outbound network calls. Air-gapped mode disables all external calls using a local vulnerability database โ€” see Configuration โ†’ Air-gapped mode.


← PullGuard home Configuration reference →