First scan, in 2 minutes.

Install the open-source WOMBATpass CLI, download the Wombat controls, and scan a sample Terraform file. No cloud credentials, no black box, just static analysis on your Infrastructure-as-Code.

v1.1.0
WOMBATpass CLI
8
Pillars
100+
Controls
Docker
Compose ready
Apache 2.0
Code license

Your code never leaves the room.

WOMBATpass parses Terraform plans locally — no cloud account, no upload, no network round trip. Review the plan and the lock file on an air-gapped machine, then decide what to send.

Static analysis only: the CLI reads your Infrastructure-as-Code and reports findings. Nothing is executed, and nothing leaves your machine unless you push it to your own server.

Wombat reviewing a Terraform plan at an air-gapped workstation

Prefer a one-liner? The installer sets up the CLI and controls for you.

macOS / Linux
bash
$curl -fsSL https://wombat-cli.dev/install.sh | sh
Windows
powershell
$irm https://wombat-cli.dev/install.ps1 | iex

One clear path for every use case.

Start with the 2-minute CLI quickstart. Switch tabs when you're ready for the dashboard, CI, or manual setup.

Get your first result in 2 minutes.

Follow the four steps below. Each command is designed to give you a guaranteed, readable result on your first try.

1

Install the CLI

WOMBATpass is published to PyPI as wafpass-core. Python 3.11+ is recommended.

bash
$pip install wafpass-core $wombat --version
2

Download the controls

The Wombat controls catalog contains the 100+ rules WOMBATpass uses to evaluate your code.

bash
$git clone https://github.com/WAF2p/framework.git controls-src $cp -r controls-src/modules/controls/controls ./controls

Recommended: clone the controls repo. Alternative: download the controls zip from the WOMBATpass page and extract it to controls/.

3

Save a sample Terraform file

Create a minimal main.tf. This example deliberately leaves a public S3 bucket so WOMBATpass has something to flag.

provider "aws" {
  region = "eu-central-1"
}

resource "aws_s3_bucket" "public" {
  bucket = "wafpp-first-check-demo"
}

resource "aws_s3_bucket_public_access_block" "public" {
  bucket                  = aws_s3_bucket.public.id
  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}
4

Run your first check

Point WOMBATpass at the current directory and print the JSON summary.

bash
$wombat check . --output json | jq '.summary'

You should see output like this:

{
  "total_controls": 100,
  "passed": 98,
  "failed": 2,
  "pillars": {
    "security": { "passed": 18, "failed": 2 }
  }
}
98 passed, resources met the control
2 failed, resources violated a control (here, the public S3 bucket)
100 controls, total rules evaluated across 8 Wombat pillars

Share it: turn this JSON into a WOMBATpass score card →

The same result, visualized, if you add the dashboard later:

Run the full dashboard locally.

The WAF2p/pass monorepo ships a unified docker-compose.yml. It brings up the CLI, server, dashboard, PostgreSQL, and Keycloak in one command.

bash
$git clone https://github.com/WAF2p/pass.git $cd pass $cp .env.example .env $# Edit .env, set POSTGRES_PASSWORD, WAFPASS_JWT_SECRET, etc. $docker compose up -d
ServiceURLDescription
wafpass-dashboardhttp://localhost:3000React dashboard
wafpass-serverhttp://localhost:8000FastAPI REST API
Keycloak (SSO)http://localhost:8080Identity provider (admin / admin)
postgreslocalhost:5432PostgreSQL database

Once the containers are healthy, seed your first dashboard view with the demo command or by pushing a scan result:

bash
$wombat demo # creates sample data and opens the dashboard $open http://localhost:3000
View full docker-compose.yml
services:

  # ── PostgreSQL ────────────────────────────────────────────
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER:     ${POSTGRES_USER:-wafpass}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-wafpass}
      POSTGRES_DB:       ${POSTGRES_DB:-wafpass}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./keycloak/init.sql:/docker-entrypoint-initdb.d/01-keycloak-db.sql:ro
    ports:
      - "${POSTGRES_PORT:-5432}:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-wafpass} -d ${POSTGRES_DB:-wafpass}"]
      interval: 5s
      timeout: 5s
      retries: 10

  # ── wafpass-server ────────────────────────────────────────
  wafpass-server:
    build:
      context: .
      dockerfile: wafpass-server/Dockerfile
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DATABASE_URL:               postgresql+asyncpg://${POSTGRES_USER:-wafpass}:${POSTGRES_PASSWORD:-wafpass}@postgres:5432/${POSTGRES_DB:-wafpass}
      WAFPASS_ENV:                ${WAFPASS_ENV:-local}
      CORS_ORIGINS:               ${API_URL:-http://localhost:3000},http://wafpass-dashboard,http://cloud.waf2p
      WAFPASS_CONTROLS_DIR:       ${WAFPASS_CONTROLS_DIR:-/app/controls}
      WAFPASS_JWT_SECRET:         ${WAFPASS_JWT_SECRET:-change-me-in-production}
      WAFPASS_JWT_EXPIRE_MINUTES: ${WAFPASS_JWT_EXPIRE_MINUTES:-60}
      WAFPASS_JWT_REFRESH_DAYS:   ${WAFPASS_JWT_REFRESH_DAYS:-7}
      WAFPASS_ADMIN_USERNAME:     ${WAFPASS_ADMIN_USERNAME:-admin}
      WAFPASS_ADMIN_PASSWORD:     ${WAFPASS_ADMIN_PASSWORD:-admin}
      WAFPASS_ADMIN_ROLE:         ${WAFPASS_ADMIN_ROLE:-admin}
      WAFPASS_API_KEY:            ${WAFPASS_API_KEY:-key}
    ports:
      - "8000:8000"

  # ── Keycloak (SSO / IdP — dev mode) ──────────────────────
  keycloak:
    image: quay.io/keycloak/keycloak:26.1
    command: start-dev
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      KC_DB:                   postgres
      KC_DB_URL:               jdbc:postgresql://postgres:5432/${KEYCLOAK_DB:-keycloak}
      KC_DB_USERNAME:          ${KEYCLOAK_DB_USER:-keycloak}
      KC_DB_PASSWORD:          ${KEYCLOAK_DB_PASSWORD:-keycloak}
      KEYCLOAK_ADMIN:          ${KEYCLOAK_ADMIN_USER:-admin}
      KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin}
      KC_HTTP_ENABLED:         "true"
      KC_HOSTNAME_STRICT:      "false"
      KC_HEALTH_ENABLED:       "true"
    ports:
      - "${KEYCLOAK_PORT:-8080}:8080"
    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:8080/health/ready || exit 1"]
      interval: 15s
      timeout: 5s
      retries: 20
      start_period: 60s

  # ── wafpass-dashboard ─────────────────────────────────────
  wafpass-dashboard:
    build:
      context: ./wafpass-dashboard
      dockerfile: Dockerfile
    restart: unless-stopped
    depends_on:
      - wafpass-server
    ports:
      - "3000:80"

volumes:
  postgres_data:

Add to CI / pre-commit.

Block non-compliant infrastructure before it reaches your main branch. WOMBATpass runs entirely on the files in the repo, so CI checks are fast and require no cloud secrets.

1

Install the pre-commit hook

Run the install script from the WOMBATpass repository once per clone. After that, every git commit is checked automatically.

bash
$bash hooks/install.sh # macOS / Linux / Git Bash $.\hooks\install.ps1 # Windows PowerShell
2

Add WOMBATpass to GitHub Actions

Use the official WOMBATpass GitHub Action to fail pulls that introduce misconfigurations. Works with public and private repositories.

Set up WOMBATpass Action

Advanced / manual setup.

Install only the components you need. Start with the CLI for CI/CD, then add the server and dashboard when you need persistence and visual exploration.

1

Install wombat CLI

Core evaluation engine: parse IaC, evaluate controls, generate reports.

From PyPI (recommended)

bash
$pip install wafpass-core $uv add wafpass-core # recommended for Python projects

From source

bash
$git clone https://github.com/WAF2p/pass.git $cd pass $uv pip install -e . # recommended $pip install -e ".[pdf]" # with PDF report support

macOS (Apple M-series)

bash
$brew install git python uv $git clone https://github.com/WAF2p/pass.git && cd pass $uv pip install -e . $wombat --version # verify installation
2

Install wafpass-server

FastAPI persistence layer: stores runs, waivers, secret findings, and audit events.

From PyPI (recommended)

bash
$pip install wafpass-server $uv add wafpass-server # recommended for Python projects

Configure & start

bash
$cp .env.example .env # set DATABASE_URL and JWT secret $alembic upgrade head # apply database migrations $uvicorn wafpass_server.main:app --reload --port 8000

API docs available at http://localhost:8000/api/docs

3

Install wafpass-dashboard

React web dashboard: 22+ compliance views, evidence export, RBAC.

bash
$git clone https://github.com/WAF2p/wafpass-dashboard.git $cd wafpass-dashboard $npm install $cp .env.example .env.local # set VITE_API_URL $npm run dev # dev server at http://localhost:5173

Common issues & fixes.

Quick answers if something doesn't work on the first try.

Controls not found

If wombat check reports "controls directory not found", the CLI will display download instructions automatically. Make sure the controls/ folder sits next to where you run scans.

Port already in use

Use a different port for the server or dashboard:

$uvicorn wafpass_server.main:app --port 8001 $npm run dev -- --port 5174
Database connection errors

Verify PostgreSQL is running and your DATABASE_URL is correct:

$psql $DATABASE_URL -c "SELECT 1"
Docker build fails

Ensure all three repositories are cloned side-by-side in the same parent directory when building from source:

$ls -1 pass/ wafpass-server/ wafpass-dashboard/

You're in control.

Local by default, explicit by design. You choose what is scanned, what is stored, and what leaves your machine — WOMBATpass never needs your cloud credentials.