T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/create_tables.sql:4- Finding
Checkpoint Tables Are Created Without Row-Level Access Controls
- Content
View full analysis
Vulnerability Details
File Location:
scripts/create_tables.sql:4-24
Vulnerability Type: Missing row-level authorization controls
Risk Level: HighVulnerable Code:
sql CREATE TABLE IF NOT EXISTS langgraph_checkpoints ( thread_id TEXT NOT NULL, checkpoint_ns TEXT NOT NULL DEFAULT '', checkpoint_id TEXT NOT NULL, parent_checkpoint_id TEXT, type TEXT, checkpoint JSONB NOT NULL, metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id) ); CREATE TABLE IF NOT EXISTS langgraph_writes ( thread_id TEXT NOT NULL, checkpoint_ns TEXT NOT NULL DEFAULT '', checkpoint_id TEXT NOT NULL, task_id TEXT NOT NULL, idx INTEGER NOT NULL, channel TEXT NOT NULL, type TEXT, blob JSONB, PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id, task_id, idx) );Technical Analysis
The installation script creates tables containing complete serialized LangGraph checkpoints, metadata, and pending writes, but it does not enable row-level security, define authorization policies, revoke broad role privileges, or associate rows with a server-validated tenant identity.
The
thread_idandcheckpoint_nscolumns provide logical identifiers, not authorization boundaries. If Supabase API roles have privileges on these tables, PostgREST can expose the data without enforcing ownership of the supplied thread identifier. Application code that accepts a caller-selectedthread_idwould likewise have no database-level protection against cross-thread access.Attack Path
- An attacker obtains a valid Supabase API key for a role that can access tables in the exposed schema, such as a publicly distributed project key where table grants remain available.
- The attacker calls the PostgREST endpoints for
langgraph_checkpointsorlanggraph_writes. - Because the insta ...[truncated 975 chars]
- Remediation
View remediation
Remediation Suggestions
- Enable and force row-level security on both tables:
sql ALTER TABLE langgraph_checkpoints ENABLE ROW LEVEL SECURITY; ALTER TABLE langgraph_checkpoints FORCE ROW LEVEL SECURITY; ALTER TABLE langgraph_writes ENABLE ROW LEVEL SECURITY; ALTER TABLE langgraph_writes FORCE ROW LEVEL SECURITY; - Revoke default access from broad API roles unless direct table access is explicitly required:
sql REVOKE ALL ON langgraph_checkpoints FROM anon, authenticated; REVOKE ALL ON langgraph_writes FROM anon, authenticated; - Add a non-null tenant or owner identifier derived from authenticated server-side context. Do not treat a caller-provided
thread_idas proof of ownership. - Create narrowly scoped
SELECT,INSERT,UPDATE, andDELETEpolicies that compare the row owner with a trusted authenticated identity. - Prefer security-reviewed RPC functions that expose only the minimum checkpoint operations and validate tenant ownership internally.
- Test access with every Supabase role to confirm that cross-tenant reads and writes are rejected.
- Enable and force row-level security on both tables:
