Supabase Credential Impact Assessor
A safe-by-default, read-only command-line tool for inventorying a leaked Supabase credential and assessing its blast radius during an authorized security assessment.
⚠️ Authorized use only. This tool is intended for internal product security teams triaging a credential leak they are authorized to assess. It defaults to non-destructive, read-only checks. Any write/delete or account creation behaviour is disabled unless you explicitly opt in.
The goal is impact assessment, not exploitation: quickly determine what a leaked key can reach so the owning product team can rotate it and remediate.
Features
Nine phases, mapped to the assessment workflow:
| Phase | Name | What it does | Network |
|---|---|---|---|
| 1 | Credential Identification | Decode the JWT (header, payload, role, issuer, audience, expiry, project ref, custom claims); classify key kind | none |
| 2 | Project Discovery | Fingerprint project URL, ref, region hint, API version, server headers | read-only |
| 3 | Permission Enumeration | Reachability of REST, Storage, Edge Functions, Auth, Realtime | read-only |
| 4 | Database Enumeration | List tables/views/RPCs via PostgREST OpenAPI; SELECT … LIMIT 1 |
read-only* |
| 5 | Storage Enumeration | List buckets, classify public/private, list objects | read-only* |
| 6 | Auth Enumeration | Signup/magic-link/reset/admin exposure via GoTrue settings | read-only* |
| 7 | Privilege Matrix | Per-resource SELECT/INSERT/UPDATE/DELETE/EXEC/Storage/Realtime grid | — |
| 8 | Evidence Collection | Write report.md, report.html, raw.json, summary.json, logs/, screenshots/ |
— |
| 9 | Attribution Assistance | Collect non-sensitive identifiers to help owners trace the key | — |
* Optional intrusive validation is off by default — see below.
Safety model
- Default: only read-only and metadata probes run.
SELECTfetches at most one row and records column names only, never values. --write-probes: enables non-destructive write validation:- INSERT →
POST [](empty array, inserts zero rows) - UPDATE →
PATCHwith an impossible filter (matches zero rows) - DELETE →
DELETEwith an impossible filter (matches zero rows) - Storage → uploads one uniquely-named temp object and immediately deletes it; RPCs are probed with an invalid argument signature so the function body never executes.
- INSERT →
--active: enables auth actions that can create a real user (signup). Off by default; use only with explicit authorization.- The raw key is never written to disk — only a truncated SHA-256 fingerprint is stored in the evidence.
- Every request is logged to
logs/assessment.logand the console.
Install
cd tools/supabase-cred-assessment
python3.12 -m venv .venv && source .venv/bin/activate
pip install -e .
# or, without installing:
pip install -r requirements.txt
Usage
# Safe, read-only assessment (recommended default). Key is prompted securely.
supabase-assess --url https://YOURREF.supabase.co
# Provide the key non-interactively and choose an output directory.
supabase-assess -u https://YOURREF.supabase.co -k "<leaked-key>" -o ./out
# Opt into non-destructive write/delete validation.
supabase-assess -u https://YOURREF.supabase.co --write-probes
# Opt into auth actions that can create a real user (authorized only).
supabase-assess -u https://YOURREF.supabase.co --write-probes --active
# Run as a module:
python -m supabase_assessor --url https://YOURREF.supabase.co
Output
Written to the output directory (default ./assessments/supabase-<timestamp>/):
report.md Human-readable Markdown report
report.html Self-contained styled HTML report
raw.json Complete assessment: every probe and result
summary.json Compact machine-readable summary
logs/ assessment.log — full request audit trail
screenshots/ Placeholder for manual evidence
Each report contains: Executive Summary, Technical Findings, Risk Rating, Affected Resources (privilege matrix), Credential Details, Evidence (probe log), Attribution Assistance, and Recommended Mitigation.
Web UI (no install, browser-only)
A static, dependency-free web edition lives at web/index.html.
Open it directly in a browser (or serve the folder) — there is no build step
and no backend:
# Just open it:
xdg-open web/index.html # or: open web/index.html (macOS)
# ...or serve the folder locally:
python -m http.server -d web 8000 # then visit http://localhost:8000
Paste the Supabase URL and key and click Run assessment. The JWT is decoded
and all read-only phases run client-side; results, the privilege matrix, and
downloadable raw.json / report.md / report.html are produced in the tab.
The key stays in memory only and is never stored or transmitted anywhere except
to the project you name.
Browser limitation — graceful degradation: some probes depend on the target
returning permissive CORS headers. If the browser blocks a response, that probe
is marked ⨯ browser/CORS blocked and, if everything is blocked, the UI shows
the equivalent CLI command so you can run the full Python tool instead.
How the assessment works
- Decode, don't guess. The key is first decoded locally (Phase 1). Supabase legacy keys are JWTs, so the role/issuer/expiry/project-ref are read straight from the token with zero network traffic.
- Fingerprint the project (Phase 2) via the PostgREST root, which also yields the exposed schema and server metadata.
- Map the surface, safely. The PostgREST OpenAPI document (Phase 4) lists
every exposed table/view/RPC without touching
information_schemaor any data. Each relation is then probed with a singleSELECT … LIMIT 1that records column names only. - Classify every outcome through one shared mapper so
SELECT, storage, and auth results all speak the same vocabulary — that consistency is what makes the Phase 7 privilege matrix trustworthy. - Score and report. Findings and an overall risk rating are derived from the probe results and written to JSON/Markdown/HTML evidence (Phase 8), plus non-sensitive attribution identifiers (Phase 9) the owning team can trace.
Writes are never attempted unless you opt in, and even then only via provably zero-effect techniques (empty-array insert, impossible-filter update/delete, temp-object upload+delete, non-executing RPC signature probe).
Build a release artifact
The CLI is a standard PEP 517 project (setuptools backend). To build the sdist + wheel that you can attach to a GitHub Release:
cd tools/supabase-cred-assessment
python -m pip install --upgrade build
python -m build # writes dist/*.tar.gz and dist/*.whl
Install the built wheel anywhere with:
pip install dist/supabase_credential_assessor-1.0.0-py3-none-any.whl
(dist/ is git-ignored so build outputs never land in the repo.)
Development
pip install -e ".[dev]"
pytest # offline unit tests (JWT decode + classifier)
ruff check supabase_assessor # lint
black --check supabase_assessor # formatting
mypy supabase_assessor # type check (advisory)
Releasing
Releases are automated by GitHub Actions
(.github/workflows/release.yml). Because
this repository ships two independent packages, each is released with its own
tag prefix — this package uses supabase-credential-assessor-vX.Y.Z.
- Update the version in
supabase_assessor/__init__.py(__version__) and add aCHANGELOG.mdentry. - Commit the changes.
- Push a version tag:
git tag supabase-credential-assessor-v1.2.3 git push origin supabase-credential-assessor-v1.2.3
- GitHub Actions builds the sdist + wheel, runs
twine check, generatesSHA256SUMS, and creates a GitHub Release with auto-generated notes and the assets attached. - A final version (
X.Y.Z) is published to PyPI; a pre-release such as1.2.3rc1is published to TestPyPI. Both use OIDC Trusted Publishing (no API tokens).
Alternatively, run the Manual Release workflow from the Actions tab
(workflow_dispatch) to bump the version, test, build, and release — with
prerelease / draft / publish-to-index toggles.
One-time setup: on PyPI (and TestPyPI) add a Trusted Publisher for this package pointing at repo
ajtazer/ajtazer, workflowrelease.yml, and environmentpypi-supabase-credential-assessor(respectivelytestpypi-supabase-credential-assessor). Each package uses its own environment so the two configs stay distinct — PyPI rejects duplicate pending-publisher configs.
Architecture
supabase_assessor/
models.py Typed dataclasses (single source of truth)
http_client.py Async httpx client: logging + retry/backoff
classify.py Status-code -> AccessResult normalisation
logging_config.py Rich console + file logging
phase1_jwt.py Phase 1 (offline)
phase2_discovery.py Phase 2
phase3_permissions.py Phase 3
phase4_database.py Phase 4
phase5_storage.py Phase 5
phase6_auth.py Phase 6
phase7_matrix.py Phase 7 (matrix rendering)
phase9_attribution.py Phase 9
analysis.py Findings + overall risk rating
reporting.py Phase 8 (JSON/Markdown/HTML)
orchestrator.py Runs all phases with a progress bar
cli.py Typer CLI entry point
web/index.html Static, browser-only edition (no build step)
tests/ Offline unit tests
pyproject.toml Packaging metadata (PEP 517, setuptools)
License
MIT. Provided for authorized defensive security assessment only.
Metadata
Release files for supabase-credential-assessor 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| supabase_credential_assessor-1.0.0.tar.gz | 38.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| supabase_credential_assessor-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 80.8 kB
Release files / supabase_credential_assessor-1.0.0.tar.gz
| Download URL | supabase_credential_assessor-1.0.0.tar.gz |
|---|---|
| Size | 38.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3ee9840ccde879da47c86f21fb7e75c9bc660647f7a5bf27a71b7c28723e76b5
|
|
BLAKE2b-256 checksum How to use checksums |
3809d82e85a8c0c5a112597d35777026dd2772d81157ee7cf099c3da007d43b9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.
Transparency logRelease files / supabase_credential_assessor-1.0.0-py3-none-any.whl
| Download URL | supabase_credential_assessor-1.0.0-py3-none-any.whl |
|---|---|
| Size | 42.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
36f947cddca64beceda01894f598df70cd3515683f0ddc817142c4de9cbbe073
|
|
BLAKE2b-256 checksum How to use checksums |
fc6ea5e95ca16a2da5d4240ea6c779c5e08833c29f0472c087ed9edeb63a8a4b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.
Transparency log