credentials_entity leak means any Trial user can harvest all production API keys for every Enterprise customer. This is a platform-wide credential compromise waiting to happen.
This audit assumes a "compromised user" or "malicious tenant" profile. We evaluate the efficacy of Row-Level Security (RLS) and database-level functions to prevent cross-tenant data access (BOLA) and unauthorized privilege escalation.
Primary Attack Surface: 0 database tables exposed via PostgREST/Supabase API.
The platform's central credential vault — `credentials_entity` — stores every third-party integration secret for every tenant: Stripe payment keys, OpenAI API keys, Slack bot tokens, and webhook signing secrets. A user with a standard Trial account can call the database API directly and retrieve the complete credential payload for every Enterprise organization on the platform in a single request.
When users connect external services (Google, GitHub, HubSpot, Slack) to their democompany workflows, the platform stores their live OAuth bearer tokens in `oauth_access_tokens` and their persistent refresh tokens in `oauth_refresh_tokens`. Both tables have no access controls. Any authenticated user can retrieve the current session token for any connected account across any organization.
democompany issues long-lived API keys for programmatic platform access. These keys are stored in `user_api_keys` with no row-level restrictions. Unlike session tokens, API keys do not expire by default and are not invalidated by a password reset — making them the most dangerous credential type on the platform. All keys for all users are accessible via a single authenticated REST call.
Every time a workflow runs on the platform, its full input and output data is persisted in `execution_entity` (run metadata) and `execution_data` (raw payload). These tables contain everything that has ever been processed by any workflow on the platform — customer records passed to AI nodes, financials from CRM integrations, and any files uploaded through webhook triggers. Both tables are fully readable by any authenticated user.
Both the end-user directory (`user`) and internal staff directory (`admin_users`) are readable by any authenticated platform user. The `admin_users` table contains hashed passwords, email addresses, role assignments, and 2FA configuration for all internal democompany staff. The `user` table contains the same data for every end-user on the platform.
The `client_users` table is the master directory that maps every user to their organization. It contains email addresses, client IDs, role names, and account status. With no access controls, any Trial account can enumerate democompany's entire customer base — including user counts per organization, which reveals which clients are heavy users of the platform.
The user_profiles table correctly enforces RLS for ownership, but the raw_metadata column is included in the default public SELECT policy. This exposes internal feature flags, subscription tiers, and billing lifecycle status to any user who can view a profile.
raw_metadata column from public access.
While core entity tables use UUIDs, the audit_logs and system_events tables use sequential BIGINT primary keys. A malicious actor can use "ID Sampling" to estimate total platform activity, daily growth rates, and customer volume with high precision.
Deterministic checks performed against the analyzed schema:
No significant architectural risks identified.
Log only. No traffic blocking. Risk measurement phase.
Enforce RLS on all sensitive tables. Reject non-tenant traffic.
Full cryptographic verification of all access paths.
Apply these patches in your development environment first.
-- [REDACTED] Tier-2 Hardening Patch for credentials_entity
-- Current Vulnerability: Policy relies on nested join which can be bypassed.
-- 1. DROP weak policy
DROP POLICY IF EXISTS "Users can view project credentials" ON credentials_entity;
-- 2. APPLY Hardened Forensic Policy
-- This forces a direct check against the project ownership
-- and eliminates the "Structural Bridge" via the comments table.
CREATE POLICY "Forensic-Hardened: Tenant Project Isolation"
ON credentials_entity
FOR SELECT
TO authenticated
USING (
EXISTS (
SELECT 1 FROM projects
WHERE projects.id = credentials_entity.project_id
AND projects.owner_id = auth.uid()
)
);