This project is currently in experimental stage (v0.x). Security patches will be applied to the latest version only.
| Version | Supported |
|---|---|
| 0.1.x | ✅ |
All user-provided inputs (schema names, table patterns, role names, policy names) are validated to prevent SQL injection attacks before being used in SQL generation.
Validation Rules:
- Schema/Identifiers: Must start with a letter or underscore, contain only alphanumeric, underscore, or dollar sign characters, and cannot be SQL keywords
- LIKE Patterns: Only alphanumeric, underscore (
_), and percent (%) characters allowed - Roles: Validated as identifiers with comma-separated list support
- Maximum Length: All inputs limited to 63 characters (PostgreSQL limit)
Example of Rejected Inputs:
// ❌ SQL injection attempts - all rejected
enableRLS({
schema: "public'; DROP SCHEMA public; --", // Contains semicolon and SQL injection
excludePatterns: ["' OR '1'='1"], // SQL injection in pattern
targetRoles: ['DROP', 'SELECT'], // SQL keywords
});Connection String Security:
- Connection strings must use service role or a role with
BYPASSRLSprivilege - Never commit
.envfiles containing real credentials to version control - Use environment variables for production deployments
- Rotate credentials immediately if accidentally exposed
Best Practices:
# ✅ Good - use environment variables
export DATABASE_URI="postgresql://postgres:[password]@[host]:5432/postgres"
pnpm payload-supabase-rls enable
# ❌ Bad - hardcoded in scripts
DATABASE_URI="postgresql://postgres:password123@..." pnpm rls:enableSecurity Model:
This library creates deny-all policies by default:
- All
SELECT,INSERT,UPDATE,DELETEoperations are denied foranonandauthenticatedroles - This blocks Supabase's PostgREST API, Auth, and Realtime features
- Only
postgresandservice_roleroles can bypass RLS
Important Limitations:
⚠️ Not suitable for multi-tenant applications - denies all access to standard roles⚠️ Blocks Supabase features - PostgREST, Auth, Realtime will not work⚠️ Overwrites existing policies - policies with the same name will be replaced
Use Case:
This library is designed for PayloadCMS-exclusive database access where:
- Only PayloadCMS connects to the database (via service role)
- No direct client access is needed
- Supabase features (Auth, Realtime, PostgREST) are not used
Development vs Production:
- ✅ Development: Auto-enable RLS using PayloadCMS plugin (
autoEnable: true) - ❌ Production: Disable auto-enable (
autoEnable: false) and apply RLS manually or via CI/CD
Recommended Configuration:
// payload.config.ts
import { payloadSupabaseRLS } from '@sect/payload-supabase-rls/integrations/payload';
export default buildConfig({
plugins: [
payloadSupabaseRLS({
autoEnable: true,
environments: ['development'], // Only in development
}),
],
});Pre-deployment Checklist:
-
Verify RLS Status:
pnpm payload-supabase-rls verify --connection $DATABASE_URI -
Check Supabase Dashboard:
- Security Advisor → 0 RLS-related errors
- Table Editor → All tables show "RLS Enabled"
-
Test Application:
- Ensure PayloadCMS admin panel works correctly
- Verify all CRUD operations function as expected
- Confirm no unauthorized access is possible
-
Monitor Logs:
- Check for permission denied errors
- Verify service role connections succeed
- Deny-all policies only: Cannot create custom RLS policies
- Policy name conflicts: Overwrites existing policies with the same name
- No policy customization: Cannot specify custom policy expressions
- Schema-wide operation: Cannot selectively enable RLS on specific tables
- PostgreSQL 9.5+: RLS support required
- Supabase PostgreSQL: Fully compatible
- Self-hosted PostgreSQL: Requires
BYPASSRLSprivilege for service role
DO NOT open public GitHub issues for security vulnerabilities.
Instead, please report security issues by:
- Email: Send to the repository maintainer (check
package.jsonfor contact info) - GitHub Security Advisories: Use "Report a vulnerability" in the Security tab
What to Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
Response Time:
- Initial response: Within 48 hours
- Security patch: Within 7 days for critical issues
- Public disclosure: After patch is released and users have had time to update
- Always validate inputs when building custom RLS policies
- Use environment variables for database connection strings
- Rotate credentials if accidentally exposed
- Test RLS policies in staging environment before production
- Monitor database logs for unauthorized access attempts
- Keep dependencies updated (run
pnpm updateregularly)
- Never commit credentials to version control
- Use secretlint before committing (automatically runs via pre-commit hook)
- Write tests for all security-sensitive code
- Follow input validation patterns from
src/core/validators.ts - Use safe SQL generation with parameterized queries or
format()
This project uses automated security scanning:
- secretlint: Detects leaked credentials in commits
- pre-commit hooks: Runs security checks before every commit
- dependency scanning: Use
pnpm auditto check for vulnerable dependencies
Run Security Checks:
# Check for secrets in all files
pnpm secretlint
# Audit dependencies for vulnerabilities
pnpm audit
# Run all tests (includes security validation tests)
pnpm test