mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-31 07:44:21 +00:00
feat(supabase): add project, auth, storage and database checks
- Read project SSL, network, Data API, backup and API key settings - Evaluate Supabase Auth hardening from the project auth config - Report public Storage buckets - Surface Postgres posture from the Supabase security advisor - Add project filtering, region-aware findings and configurable thresholds
This commit is contained in:
1 parent
4ab20d4489
commit
4b4175c495
157 files changed
+5156
-59
No files matched your search
@@ -221,6 +221,15 @@ Only fields with a numeric range, a fixed value set, or a length cap are listed.
|
||||
| `max_owner_percentage` | `1..50` % | guidance recommends ≤25% |
|
||||
| `max_owners` | `1..1000` | absolute cap, overrides percentage for large teams |
|
||||
|
||||
### Supabase
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `max_retries` | `0..10` | Management API retries |
|
||||
| `postgrest_max_rows` | `1..1000000` rows | Supabase default is 1000; lower is safer |
|
||||
| `auth_password_min_length` | `6..128` characters | Supabase default is 6; 8 or more recommended |
|
||||
| `auth_otp_expiry_seconds` | `60..86400` seconds | Supabase advisor flags expiries above one hour |
|
||||
|
||||
These bounds live in the provider schemas under `prowler/config/schema/`; each field's `Field(ge=..., le=...)` (or `field_validator`) is the source of truth and the descriptions there carry the full rationale.
|
||||
|
||||
This approach ensures that checks are easily configurable, making Prowler highly adaptable to different environments and requirements.
|
||||
@@ -296,6 +296,16 @@ The following list includes all the Vercel checks with configurable variables th
|
||||
| `team_member_role_least_privilege` | `max_owners` | Integer | `3` |
|
||||
| `team_no_stale_invitations` | `stale_invitation_threshold_days` | Integer | `30` |
|
||||
|
||||
## Supabase
|
||||
|
||||
The following list includes all the Supabase checks with configurable variables that can be changed in the configuration YAML file:
|
||||
|
||||
| Check Name | Value | Type | Default |
|
||||
|----------------------------------------|----------------------------|---------|---------|
|
||||
| `projects_postgrest_max_rows_limited` | `postgrest_max_rows` | Integer | `1000` |
|
||||
| `auth_password_min_length` | `auth_password_min_length` | Integer | `8` |
|
||||
| `auth_otp_expiry_within_threshold` | `auth_otp_expiry_seconds` | Integer | `3600` |
|
||||
|
||||
## Okta
|
||||
|
||||
### Configurable Checks
|
||||
@@ -890,6 +900,20 @@ github:
|
||||
# github.repository_inactive_not_archived
|
||||
inactive_not_archived_days_threshold: 180
|
||||
|
||||
# Supabase Configuration
|
||||
supabase:
|
||||
# Maximum retries for Management API requests (0 disables retries)
|
||||
max_retries: 3
|
||||
# supabase.projects_postgrest_max_rows_limited
|
||||
# Maximum rows a single Data API request may return
|
||||
postgrest_max_rows: 1000
|
||||
# supabase.auth_password_min_length
|
||||
# Minimum password length Supabase Auth must enforce
|
||||
auth_password_min_length: 8
|
||||
# supabase.auth_otp_expiry_within_threshold
|
||||
# Maximum validity of email one-time passcodes, in seconds
|
||||
auth_otp_expiry_seconds: 3600
|
||||
|
||||
# Vercel Configuration
|
||||
vercel:
|
||||
# vercel.deployment_production_uses_stable_target
|
||||
|
||||
@@ -2,41 +2,34 @@
|
||||
title: "Supabase Authentication in Prowler"
|
||||
---
|
||||
|
||||
Prowler for Supabase authenticates to the hosted Supabase Management API using a **Personal Access Token** (PAT). Prowler reads the token exclusively from `SUPABASE_ACCESS_TOKEN`; there is no credential CLI argument, and Prowler does not read Supabase CLI state files.
|
||||
Prowler authenticates to the Supabase Management API with a Personal Access Token (PAT) read from the `SUPABASE_ACCESS_TOKEN` environment variable. The token is never accepted on the command line, so it does not end up in shell history or process listings.
|
||||
|
||||
## Personal Access Token Security
|
||||
## Create a Personal Access Token
|
||||
|
||||
Supabase PATs inherit the privileges of the user account that created them. Use a dedicated least-privilege or read-only organization account where available, set a suitable token expiry, store the token in a secret manager, and rotate it regularly.
|
||||
|
||||
<Warning>
|
||||
A PAT is not independently scoped to read-only Management API access. Compromise of the token grants the same Management API privileges as its issuing user account.
|
||||
</Warning>
|
||||
|
||||
## Required Access
|
||||
|
||||
The issuing account must be able to call:
|
||||
|
||||
- [`GET /v1/organizations`](https://supabase.com/docs/reference/api/v1-list-all-organizations)
|
||||
- [`GET /v1/organizations/{slug}/members`](https://supabase.com/docs/reference/api/v1-list-organization-members)
|
||||
|
||||
An invalid token returns `401`, insufficient organization permissions return `403`, and rate limiting returns `429`. Prowler treats all three as scan errors rather than compliant results. Supabase applies a standard limit of approximately 120 Management API requests per minute for each user and scope; Prowler uses the response rate-limit reset headers before retrying.
|
||||
|
||||
## Configure Authentication
|
||||
|
||||
Create a PAT from [Supabase Account Tokens](https://supabase.com/dashboard/account/tokens), then export it:
|
||||
1. Open the [Supabase Dashboard](https://supabase.com/dashboard/account/tokens) and go to **Account** > **Access Tokens**.
|
||||
2. Click **Generate new token**, give it a name such as `prowler-read-only`, and copy the value once.
|
||||
3. Export it before running Prowler:
|
||||
|
||||
```bash
|
||||
export SUPABASE_ACCESS_TOKEN="your-personal-access-token"
|
||||
export SUPABASE_ACCESS_TOKEN="sbp_..."
|
||||
prowler supabase
|
||||
```
|
||||
|
||||
For CI/CD, configure `SUPABASE_ACCESS_TOKEN` as a masked secret environment variable. Do not place it in command arguments, repository files, or job logs.
|
||||
## Required Access
|
||||
|
||||
## Out of Scope
|
||||
Personal Access Tokens inherit the permissions of the account that created them. The account must be a member of every organization you want to audit; Prowler reads organizations, members, projects and project configuration and never writes.
|
||||
|
||||
This proof of concept does not support:
|
||||
<Tip>
|
||||
Create the token from a dedicated organization member with the **Read-only** role where your plan supports it, enable MFA on that account, and rotate the token periodically. Prowler does not use the project `anon` or `service_role` keys.
|
||||
</Tip>
|
||||
|
||||
- OAuth 2.0 Authorization Code with Proof Key for Code Exchange (PKCE)
|
||||
- Direct PostgreSQL authentication
|
||||
- Self-hosted Supabase deployments
|
||||
- Supabase CLI credential or state files
|
||||
## Troubleshooting
|
||||
|
||||
| Error | Cause |
|
||||
|---|---|
|
||||
| `SupabaseCredentialsError` | `SUPABASE_ACCESS_TOKEN` is not set |
|
||||
| `SupabaseAuthenticationError` | The token is invalid, expired or revoked |
|
||||
| `SupabaseInsufficientPermissionsError` | The account cannot read the requested organization or project |
|
||||
| `SupabaseRateLimitError` | The Management API rate limit stayed active after the configured retries |
|
||||
|
||||
Prowler honours `X-RateLimit-Reset` and `Retry-After` headers and retries requests up to `max_retries` times (configurable in the audit configuration).
|
||||
@@ -2,17 +2,17 @@
|
||||
title: "Getting Started With Supabase on Prowler"
|
||||
---
|
||||
|
||||
Prowler for Supabase scans hosted Supabase Cloud organizations through the Management API. This proof of concept checks whether each organization member has multi-factor authentication (MFA) enabled.
|
||||
Prowler for Supabase scans hosted Supabase Cloud organizations and projects through the Management API. It covers organization membership, project platform settings, Supabase Auth configuration, Storage buckets and the Postgres security posture reported by the Supabase security advisor, without executing SQL against your databases.
|
||||
|
||||
<Warning>
|
||||
This proof of concept supports Prowler SDK and Prowler CLI only. It does not support onboarding through Prowler Cloud, Prowler Private Cloud, or Prowler Local Server; self-hosted Supabase; direct PostgreSQL access; or OAuth.
|
||||
</Warning>
|
||||
<Note>
|
||||
Supabase is supported in Prowler SDK and Prowler CLI. Self-hosted Supabase and direct PostgreSQL access are not covered.
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. A hosted Supabase Cloud account with access to at least one organization.
|
||||
2. A Supabase Personal Access Token (PAT) for an account that can list organizations and organization members.
|
||||
3. A dedicated least-privilege or read-only organization account where your Supabase plan and organization roles allow one.
|
||||
2. A Supabase Personal Access Token (PAT) for an account that can read the organizations and projects you want to audit.
|
||||
3. A dedicated read-only organization member for Prowler where your Supabase plan and organization roles allow one.
|
||||
|
||||
See [Supabase Authentication in Prowler](./authentication) for PAT setup and security guidance.
|
||||
|
||||
@@ -25,16 +25,32 @@ export SUPABASE_ACCESS_TOKEN="your-personal-access-token"
|
||||
prowler supabase
|
||||
```
|
||||
|
||||
To run only the organization member MFA check:
|
||||
Limit the scan to specific projects by reference or name:
|
||||
|
||||
```bash
|
||||
prowler supabase --check organizations_member_mfa_enabled
|
||||
prowler supabase --project abcdefghijklmnopqrst storefront
|
||||
```
|
||||
|
||||
## Checks Shipped
|
||||
Run a subset of checks:
|
||||
|
||||
| Check ID | Severity | Description |
|
||||
```bash
|
||||
prowler supabase --check projects_ssl_enforcement_enabled database_rls_enabled_on_public_tables
|
||||
```
|
||||
|
||||
## Services and Checks
|
||||
|
||||
| Service | What is audited | Management API endpoints |
|
||||
|---|---|---|
|
||||
| `organizations_member_mfa_enabled` | High | Creates one finding per organization member and fails members whose Supabase account does not have MFA enabled. |
|
||||
| `organizations` | Member MFA | `/v1/organizations/{slug}/members` |
|
||||
| `projects` | SSL enforcement, network restrictions, Data API max rows, Point-in-Time Recovery, legacy API keys | `/v1/projects`, `/v1/projects/{ref}/ssl-enforcement`, `/v1/projects/{ref}/network-restrictions`, `/v1/projects/{ref}/postgrest`, `/v1/projects/{ref}/database/backups`, `/v1/projects/{ref}/api-keys/legacy` |
|
||||
| `auth` | Leaked password protection, password length, MFA enrollment, OTP expiry, refresh token rotation, CAPTCHA, email confirmation, anonymous sign-ins | `/v1/projects/{ref}/config/auth` |
|
||||
| `storage` | Public buckets | `/v1/projects/{ref}/storage/buckets` |
|
||||
| `database` | Row Level Security, SECURITY DEFINER views, mutable `search_path`, exposed `auth.users`, leaked service keys, extensions in `public`, policies on user metadata, vulnerable Postgres versions | `/v1/projects/{ref}/advisors/security` |
|
||||
|
||||
The finding resource UID is the Management API `user_id`. Prowler does not include member email addresses in findings or normal logs.
|
||||
Project findings carry the project reference as the account scope and the project region as the finding region; organization findings use the organization slug and the `global` region.
|
||||
|
||||
Thresholds for the Data API row limit, the minimum password length and the OTP expiry are configurable; see the [configuration file](/user-guide/cli/tutorials/configuration_file#supabase).
|
||||
|
||||
## Data Handling
|
||||
|
||||
Prowler stores only the settings each check evaluates. Member email addresses, JWT secrets, provider client secrets, SMTP passwords and hook secrets returned by the Management API are discarded and never appear in findings or logs. Projects that are paused or whose advisor cannot run are skipped rather than reported as failures.
|
||||
Reference in new issue
Block a user