AI Agent Security: Hardening Supabase RLS for Enterprise Knowledge
TL;DR
- AI agents accessing sensitive enterprise data require robust, database-level access controls beyond application logic.
- Implement Supabase Row Level Security (RLS) with explicit end-user context propagation to ensure agents operate within strict user permissions.
The AI Agent's Implicit Superuser Problem
AI agents deployed within enterprise environments frequently interact with sensitive, proprietary data. This interaction presents a significant security challenge: how to ensure the agent only accesses information permissible to the user it acts on behalf of, not merely what its own service account grants. A common failure mode is granting the AI agent broad, unfettered database access, or relying solely on application-layer checks.
Consider an AI agent designed to answer questions about internal documents. If this agent connects to the database using a service role or a generic "agent" user ID, it often inherits permissions far exceeding any single end-user's scope. This creates an implicit superuser scenario: the agent can theoretically access all data it's configured to query, bypassing the granular permissions intended for individual users. Application-level filtering, while necessary, is insufficient. It is susceptible to bypasses, misconfigurations, or novel attack vectors like prompt injection that could trick the agent into requesting unauthorized data. The database itself must enforce access.
Supabase RLS: The Missing Context
Supabase Row Level Security (RLS) provides a powerful mechanism to restrict data access at the row level based on the authenticated user. A typical RLS policy might look like this:
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
owner_id UUID REFERENCES auth.users(id),
content TEXT
);
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
CREATE POLICY select_own_documents ON documents
FOR SELECT
USING (auth.uid() = owner_id);
This policy effectively restricts users to view only documents where their auth.uid() matches the owner_id. However, for AI agents, auth.uid() refers to the agent's authenticated identity, not the end-user. If the agent authenticates with its own JWT, auth.uid() will be the agent's UUID. If the agent uses a service key, RLS is bypassed entirely. The core problem: the database lacks context about the actual end-user the agent is serving. This missing context allows the agent to either see nothing (if RLS policies are too strict for its own ID) or everything (if it bypasses RLS or has a generic ID with broad RLS).
Contextual RLS: Lore's Secure Delegation Pattern
Lore addresses this by explicitly propagating the end-user's identity into the database session, allowing RLS policies to enforce permissions as if the end-user were directly querying the database. This pattern ensures the AI agent operates under the strict authorization boundaries of the human user it is assisting.
The architecture relies on a trusted backend service that mediates the AI agent's database requests. This service performs two critical steps:
- User Context Extraction: When an AI agent initiates a request, it includes the end-user's authenticated JWT. The backend service validates this JWT and extracts the
user_id. - Session Context Setting: Before executing any database query on behalf of the agent, the backend explicitly sets a session variable within the database to the extracted
user_id.
-- Example: Setting a session variable for the current user ID
SELECT set_config('app.current_user_id', 'YOUR_END_USER_UUID', false);
The set_config function sets a session-local parameter. The false argument ensures this setting is not transaction-local and persists for the duration of the connection or until explicitly unset.
With this session variable in place, RLS policies can then reference current_setting('app.current_user_id', true) to enforce access control:
-- Updated RLS policy referencing the session variable
CREATE POLICY select_documents_by_delegated_user ON documents
FOR SELECT
USING (owner_id = current_setting('app.current_user_id', true)::uuid);
Now, when the AI agent's query (routed through the trusted backend) hits the database, the RLS policy will check if owner_id matches the user_id stored in app.current_user_id, effectively enforcing the end-user's permissions. The true argument to current_setting prevents an error if the variable is not set, returning NULL instead.
This approach ensures:
- Granular Control: The agent's access is precisely aligned with the end-user's authorizations.
- Database-Level Enforcement: Security is enforced at the data layer, not just the application layer.
- Auditability: Database logs can track which
app.current_user_idwas active during agent queries.
Architectural Safeguards Beyond RLS
While contextual RLS is fundamental, a holistic security posture for AI agents requires additional safeguards:
- Least Privilege for Agent Credentials: The AI agent's own database credentials (if it has them, separate from the service key for the backend) must be severely restricted. They should only have permissions to execute
SELECT set_config(...)and then performSELECToperations on specific tables. They must not have DDL (Data Definition Language) or DML (Data Manipulation Language) privileges beyond what is absolutely necessary. - Trusted Backend Isolation: The service responsible for setting
app.current_user_idshould be a highly trusted, tightly controlled component. Its API should be robustly authenticated and authorized, ensuring only legitimate AI agent requests can trigger context switching. - Input Validation and Prompt Injection Defense: RLS prevents unauthorized data access, but it does not prevent a malicious prompt from attempting to induce the agent to ask for unauthorized data. Comprehensive input validation and prompt engineering techniques are critical to filter out such attempts at the application layer, logging any suspicious activity even if RLS ultimately blocks the database query.
- Observability and Alerting: Monitor database access patterns, especially those originating from the AI agent's backend service. Implement alerts for unusual query volumes, access attempts on sensitive tables by unexpected user IDs, or RLS denial events.
Implementing contextual RLS with a secure delegation pattern transforms an AI agent from a potential security liability into a secure, permission-aware tool. This robust architecture ensures enterprise knowledge remains protected, even as AI agents expand their operational scope.