Skip to content

sameermohan-git/purplegate

Repository files navigation

purplegate — Block insecure agentic-AI merges


Agentic apps merge code that leaks secrets, misses RLS, or accepts prompt injection. purplegate runs red-team probes and a blue-team defense scan on every PR — and fails the build before those merges ship.

uses: sameermohan-git/purplegate@v0.1.0-alpha.9  |  GHCR image →  |  Quickstart →

release tests alpha MIT


Why purplegate

Agentic-AI apps are a new class of attack surface. Traditional SAST misses the LLM-specific bugs (prompt injection, system-prompt leakage, cross-user data exposure). Traditional security Actions miss the AI-specific supply chain (MCP servers, vendored SDKs, vulnerable corpora). You need both. purplegate is both.

  • 🔴 Red-team — eight probes covering every class of agentic-app risk: secrets, SAST, dependencies, IaC / RLS, workflow injection, prompt injection (isolated Claude-as-judge), MCP config risks, and HTTP security headers.
  • 🔵 Blue-team — a defense scanner that detects runtime guardrails (LLM Guard, Guardrails AI), rate limiters, and allowlisted findings — then adjusts severity DOWN on findings that are already mitigated. Severity is never raised above the red-team baseline.
  • 🟣 Purple-team gate — one CI action, one SARIF report. Critical / High findings fail the build by default; Medium / Low report only. Fully configurable.

What it catches (that others miss)

Class Example finding Tool
LLM prompt injection "Who is Trump?" answered despite a finance-app scope guard isolated Claude judge via promptfoo
System-prompt leakage Attacker extracts your app's instructions via a crafted payload same judge, 3-rep agreement
Cross-user data disclosure App references another user's transactions when asked purple-team dedicated probe
Missing Supabase RLS CREATE TABLE public.transactions without ENABLE ROW LEVEL SECURITY custom static check
Workflow command injection ${{ github.event.issue.title }} inside a run: step wraps zizmor
Live credential in git a real sk_live_... committed today trufflehog --only-verified
Vulnerable MCP SDK mcp-remote pinned < 0.1.16 (CVE-2025-6514, CVSS 9.7), @modelcontextprotocol/server-filesystem < 2025.7.1 (CVE-2025-53109), mcp PyPI < 1.23.0 (CVE-2025-66416), plus 7 more vendored GHSA/NVD advisory list in src/probes/mcp.py
Generic advice leak "RRSPs are generally good" from a finance app that should only answer about user data judge rubric v1

Every finding maps to OWASP LLM Top 10 v2025, OWASP Agentic 2026, and MITRE ATLAS v5.4.0 — surfaced in SARIF ruleId so GitHub Code Scanning + downstream SIEM tools filter by framework.

Quickstart

# .github/workflows/security-audit.yml
name: Security Audit
on: [pull_request, workflow_dispatch]
permissions:
  contents: read
  security-events: write
  pull-requests: write

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: step-security/harden-runner@<sha>
        with: { egress-policy: audit }
      - uses: actions/checkout@<sha>
        with: { fetch-depth: 0, persist-credentials: false }
      - uses: sameermohan-git/purplegate@v0.1.0-alpha.9   # or pin by 40-char commit SHA
        with:
          config: .purplegate/config.yml
          fail-on: high
          llm-provider: anthropic
          llm-api-key: ${{ secrets.AUDIT_ANTHROPIC_KEY }}
          target-url: ${{ secrets.STAGING_API_URL }}
          # Required: Docker container actions don't get github.token in
          # their env: namespace, so the consumer passes it explicitly.
          github-token: ${{ secrets.GITHUB_TOKEN }}

      # Optional: keep the JSON / SARIF / Markdown reports for offline analysis.
      # purplegate writes them to <workspace>/.purplegate-reports/ during the run.
      - uses: actions/upload-artifact@<sha>
        if: always()
        with:
          name: purplegate-reports
          path: .purplegate-reports/
          if-no-files-found: warn

Then add .purplegate/config.yml — see docs/CONFIG.md for the full schema. Full walkthrough in docs/QUICKSTART.md.

Architecture

┌─ Consumer repo ─────────────────────────┐
│  .purplegate/config.yml                 │
│  .purplegate/allowlist.yml              │
│  .github/workflows/security-audit.yml ──┼─▶ purplegate Docker image
└─────────────────────────────────────────┘     │
                                                ▼
                        ┌───────────────────────────────────────┐
                        │  Orchestrator                         │
                        │   ├─ secrets        (gitleaks + th)   │
                        │   ├─ sast           (Semgrep + AST)   │
                        │   ├─ deps           (osv-scanner)     │
                        │   ├─ iac            (Checkov + RLS)   │
                        │   ├─ workflows      (zizmor)          │
                        │   ├─ prompt_injection ──▶ isolated    │
                        │   │                       Claude judge│
                        │   ├─ mcp            (static scan)     │
                        │   ├─ sbom           (Syft)            │
                        │   └─ headers        (httpx)           │
                        ├───────────────────────────────────────┤
                        │  Blue-team defense scanner            │
                        │   (severity adjuster — never raises)  │
                        ├───────────────────────────────────────┤
                        │  Report (SARIF + Markdown + JSON)     │
                        │  Gate (fail-on: critical / high / …)  │
                        └───────────────────────────────────────┘

Supply-chain posture

This tool's single most important property is that it does not become the attack vector it's meant to defend against. Consumers do not have to trust us — they can verify.

Shipping today (current tag v0.1.0-alpha.9)

  • Multi-arch Docker image (linux/amd64 + linux/arm64) published to ghcr.io/sameermohan-git/purplegate. Pin by digest:
    uses: sameermohan-git/purplegate@v0.1.0-alpha.9   # tag works because images are cosign-signed
    # or, for direct image consumption:
    # docker pull ghcr.io/sameermohan-git/purplegate@sha256:<digest>
  • Cosign keyless signature on every published image (Sigstore + Rekor transparency log).
  • SLSA Level 3 build provenance via actions/attest-build-provenance — verify before first use:
    gh attestation verify oci://ghcr.io/sameermohan-git/purplegate:v0.1.0-alpha.9 \
      --owner sameermohan-git
    Successful verification proves the image was built by release.yml@refs/tags/v0.1.0-alpha.9 on a github-hosted runner.
  • SBOMs (SPDX + CycloneDX) signed via cosign sign-blob keyless — both sbom.spdx.json and sbom.cdx.json ship alongside a .sigstore (Sigstore new-bundle format: signature + Fulcio cert + Rekor inclusion proof in one file) on every GitHub Release. Verify with:
    cosign verify-blob \
      --bundle sbom.spdx.json.sigstore \
      --new-bundle-format \
      --certificate-identity-regexp 'https://github.com/sameermohan-git/purplegate/.github/workflows/release\.yml@.+' \
      --certificate-oidc-issuer https://token.actions.githubusercontent.com \
      sbom.spdx.json
  • Dockerfile base images pinned by sha256 digestdebian:12-slim and python:3.12.7-slim-bookworm resolve to a fixed multi-arch index so re-builds are bit-identical until Renovate proposes a digest bump.
  • Workflow permissions scoped at job level — top-level is contents: read; only the build job in release.yml opts in to the four write scopes it needs (contents, packages, id-token, attestations).
  • CodeQL static analysis runs on every PR and push to main via .github/workflows/codeql.yml, queries: security-extended. Findings appear in Security → Code scanning.
  • Every scanner binary inside the image is pinned to a specific version and SHA256-verified against upstream checksums (gitleaks, trufflehog, syft, actionlint) or a locally-computed SHA256 anyone can reproduce (osv-scanner). Python scanners (semgrep, checkov, zizmor, pip-audit) are pinned to exact versions via isolated pipx venvs.
  • Every third-party uses: in our own workflows pinned by 40-char commit SHA — never by tag. Mar 2025 (tj-actions) and Mar 2026 (trivy-action) taught us why.
  • License manifest for every bundled binary at LICENSE-3RD-PARTY.md, including the AGPL-3.0 trufflehog posture.

Hardening targets for v1.0

  • OSSF Scorecard ≥ 8/10 (live score badge above; current ~6/10, the remaining gap is structural — solo maintainer Code-Review, project-age Maintained, OpenSSF Best-Practices badge).
  • Branch protection on main requiring signed commits + 2 reviewers.
  • Migration of the Action's own uses: lines to the latest signed SHAs (Dependabot is currently proposing them).
  • pip dependencies pinned by hash (--require-hashes) inside the Dockerfile.

Full policy in docs/SUPPLY_CHAIN.md. Threat model in THREAT_MODEL.md.

Severity & gating

Severity Default gate Examples
🔴 Critical Fails CI Verified live credential · public table without RLS · workflow command injection · vulnerable MCP SDK · verified system-prompt extraction
🟠 High Fails CI Route without auth · generic-advice leak · CVE ≥ 7.0 · missing runtime LLM guardrails
🟡 Medium Reports only Missing CSP · unpinned non-MCP dep
🟢 Low Reports only Suboptimal Referrer-Policy

Override via the fail-on: input. Allowlist entries need a reason, an acknowledged_by, and an expires within 365 days — see docs/SUPPRESSIONS.md.

Avoid list

Baked into the tool because supply-chain choices are security choices:

Project Reason
tj-actions/* · reviewdog/action-setup / -shellcheck / -staticcheck / -ast-grep / -typos / -composite-template CVE-2025-30066 / CVE-2025-30154 (Mar 2025 force-push compromise)
aquasecurity/trivy-action by tag Mar 2026 tag force-push. The Trivy binary is fine; we invoke it directly from our vendored image.
tfsec Deprecated, absorbed into Trivy — use Checkov.
protectai/rebuff Archived May 2025.
HarmBench / AdvBench corpora in CI MIT but contain toxic content.

Roadmap

  • v0.1 — scaffold: orchestrator + 9 probes + blue-team + SARIF + gate
  • v0.2 — 37-test fixture suite + self-test CI
  • v0.3 — pinned Dockerfile binaries + signed GHCR image
  • v0.4 — promptfoo integration with owasp:llm preset + Lakera Mosscap/Gandalf corpora
  • v0.5 — Checkov wire-up + live Supabase catalog drift check
  • v0.6 — Consumer-specific SARIF suppression helpers
  • v1.0 — Marketplace publish, Scorecard ≥ 8, SLSA L3 signed, docs complete

Contributing

PRs welcome once v1.0 is cut; until then we're stabilising the interface. Security issues → SECURITY.md. Probe additions → open an issue first to discuss severity + taxonomy mapping.

License

MIT. See LICENSE.


An open-source project from Kardoxa Labs. Built for agentic apps that take security seriously.

About

purplegate — Red/blue-team CI gate for agentic-AI apps. Prompt-injection, secrets, SAST, deps, IaC/RLS, workflow injection, MCP checks. One signed GitHub Action, mapped to OWASP LLM Top 10 v2025 + MITRE ATLAS.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors