Metadata-Version: 2.4
Name: db-fortress
Version: 0.1.0
Summary: PostgreSQL/Supabase database security scanner — supply-chain pivot detection + JWT bypass prober
Author: Omar Jimenez
License: MIT
Project-URL: Homepage, https://github.com/Omji-krypto/db-fortress
Project-URL: Issues, https://github.com/Omji-krypto/db-fortress/issues
Keywords: postgres,supabase,security,audit,scanner,rls,jwt
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Database
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# db-fortress

PostgreSQL / Supabase database security scanner.

Two complementary probes for production posture:

- **supply-chain pivot** — detects suspicious session bursts, long-lived sessions, OAuth identity creation spikes, and unknown superuser roles in `pg_roles`. Read-only via `psql`.
- **JWT bypass prober** — enumerates Supabase Edge Functions via the Management API and probes each one with an unauthenticated `POST {}` to surface `verify_jwt=false` exposures that are not on an explicit allowlist.

Both probes emit JSON reports with deterministic severity scoring (LOW / MEDIUM / HIGH / CRITICAL) and exit codes you can wire into CI.

## Why

Most database scanners check CVEs and dependencies. db-fortress checks **production posture** of the running database — the configuration drift that vibe-coded apps and AI-generated migrations typically ship with: weak roles, exposed Edge Functions, abnormal session patterns. It is built to run as a scheduled job and produce a signed JSON artifact, not as an interactive UI.

## Install

```bash
pip install db-fortress
```

Or from source:

```bash
git clone https://github.com/Omji-krypto/db-fortress
cd db-fortress
pip install -e .
```

## Requirements

- Python 3.10+
- `psql` on `PATH` for the `pivot` subcommand
- A Postgres connection string with read access for `pivot`
- A Supabase Management API token (`SUPABASE_ACCESS_TOKEN`) with `read:functions` for `jwt-probe`

## Usage

### Supply-chain pivot scan

```bash
export SUPABASE_DB_URL="postgresql://reader:***@db.example.supabase.co:5432/postgres"

db-fortress pivot \
    --window-hours 72 \
    --output supply-chain-pivot.json
```

Or pass the connection string explicitly:

```bash
db-fortress pivot --dburl "$SUPABASE_DB_URL" --output report.json
```

Exit codes: `0` LOW/MEDIUM, `1` HIGH, `2` CRITICAL.

### JWT bypass probe

This subcommand sends real HTTP requests to your project's Edge Functions. By design it only sends `POST {}` with no Authorization header — it does not modify state — but it **is active traffic against your project**. It is gated behind `--active`.

```bash
export SUPABASE_ACCESS_TOKEN="sbp_..."

db-fortress jwt-probe \
    --active \
    --project-ref abcdwxyz1234 \
    --baseline ./examples/baseline.example.json \
    --output jwt-bypass-probe.json
```

The baseline file declares which Edge Functions are intentionally public:

```json
{
  "ef_verify_jwt_false_allowlist": [
    "public-webhook-receiver",
    "public-health-check"
  ]
}
```

Any function returning `200/201/202/204/400/422` to an unauthenticated `POST {}` and **not** in `ef_verify_jwt_false_allowlist` is reported as `unauth_UNEXPECTED` with score 150 (CRITICAL). Functions returning `401/403` are reported as `protected`.

Exit codes: `0` LOW/MEDIUM, `1` HIGH, `2` CRITICAL.

### Without `--active`

If you call `db-fortress jwt-probe` without `--active`, the command refuses to run and prints the warning. This is intentional: you should not point an active scanner at a project unless you know what it does.

## Pro tier · early access waitlist

`db-fortress` is the open core. Pro tier adds:

- 120+ controls (vs 30 in the free CLI)
- Continuous monitoring
- Bilingual reports (EN / ES / ZH)
- Aegis VC sign per finding
- Priority support

Join the waitlist · invites sent in signup order:

https://artefactforge.ai/db-fortress

## CLI

```
db-fortress pivot [--dburl URL] [--window-hours N] [--output FILE]
db-fortress jwt-probe --active --project-ref REF [--baseline FILE] [--output FILE] [--max-functions N]
db-fortress --version
```

## Output schema

`pivot` JSON:

```json
{
  "generated": "2026-05-09T10:00:00+00:00",
  "window_hours": 72,
  "total_score": 240,
  "severity": "CRITICAL",
  "findings": [
    {"check": "session_burst", "rows_found": 4, "score": 120, "flags": ["session_burst_2026-05-09T03:00:00+00:00:62"]},
    {"check": "long_sessions", "rows_found": 12, "score": 80, "flags": ["long_sessions_count:12"]},
    {"check": "new_oauth_identities", "rows_found": 28, "score": 40, "flags": ["oauth_activity_google:8"]},
    {"check": "admin_role_assignments", "rows_found": 9, "score": 0, "flags": []},
    {"check": "table_activity", "rows_found": 50, "score": 0, "flags": [], "sample": [["public", "events", "1234", "0", "", ""]]}
  ]
}
```

`jwt-probe` JSON:

```json
{
  "generated": "2026-05-09T10:00:00+00:00",
  "project_ref": "abcdwxyz1234",
  "total_functions": 14,
  "allowlist_size": 2,
  "critical_count": 1,
  "high_count": 0,
  "findings": [
    {"slug": "internal-admin-tool", "status": 200, "verdict": "unauth_UNEXPECTED", "score": 150, "flags": ["verify_jwt_false", "NOT_allowlisted"], "body_preview": "{\"ok\":true}"}
  ]
}
```

## Severity scoring

| Score range | Severity  |
|-------------|-----------|
| ≥ 151       | CRITICAL  |
| 81 – 150    | HIGH      |
| 31 – 80     | MEDIUM    |
| 0 – 30      | LOW       |

## Safety

- The `pivot` subcommand only runs `SELECT` statements against system catalogs and `auth.*` tables.
- The `jwt-probe` subcommand only sends `POST {}` payloads. It never sends a non-empty body and never authenticates.
- Neither subcommand writes to your database.
- All output is local JSON — nothing is uploaded.

If you embed this in CI, set a low `--max-functions` and pin a baseline file in your repo so a forgotten public Edge Function fails the build.

## Roadmap

- `db-fortress baseline` — generate an initial baseline interactively
- `db-fortress sign` — Ed25519-signed JSON reports (drop-in for compliance attestations)
- Postgres-only mode (drop the Supabase Management API dependency for plain Postgres deployments)
- Coverage of additional posture checks (RLS USING `true`, BOLA detection on REST endpoints)

## Contributing

Issues and PRs welcome. Please open an issue before sending large changes — this repo intentionally stays small.

## License

MIT. See `LICENSE`.
