Hi everyone,
We’re excited to announce django-rls 1.0.0, a major security-focused release for PostgreSQL Row Level Security in Django. This is the release we’ve been building toward since 0.4.x: stronger defaults, clearer trust boundaries, and a full security regression suite.
If you’re on 0.4.x, please read the migration section below — 1.0.0 is not drop-in compatible for every app.
What’s new in 1.0.0
Security hardening
- Identity immutability —
user_idandtenant_idcan’t be silently overridden after middleware sets them. Usesystem_rls_context()for admin jobs, tests, and workers that need to act as another user. - Session tenant disabled by default — middleware no longer reads
request.session["tenant_id"]unless you explicitly opt in withALLOW_SESSION_TENANT. - Connection hygiene — stale RLS context is cleared on pooled connections at the start of each request.
- Stricter
CustomPolicyvalidation — blocks whitespace-only expressions and DML keywords in addition to the existing DDL blocklist. FORCE ROW LEVEL SECURITY— always applied when RLS is enabled.
New tooling & configuration
DJANGO_RLSsettings —REQUIRE_CONTEXT,AUDIT_LOG,STRICT_MIGRATE_RLS,ALLOW_SESSION_TENANT,TENANT_MEMBERSHIP_VALIDATOR,REGISTERED_CONTEXT_KEYS, and more.audit_rlsmanagement command — run before deploy to verify RLS/FORCE RLS and flag riskyCustomPolicydefinitions.django_rls.contextmodule — centralized, auditable context management (imports fromdjango_rls.db.functionsstill work).- 109 security regression tests — run against real PostgreSQL, not mocks.
Other improvements
- Policy context reads use the InitPlan pattern for better performance.
AUTO_ENABLE_RLS=Falseis now correctly respected.- Updated threat model and production checklist in
.github/SECURITY.md.
Breaking changes (0.4.x → 1.0.0)
| Area | 0.4.x | 1.0.0 |
|---|---|---|
Session tenant_id |
Used by default | Off unless ALLOW_SESSION_TENANT=True |
Override user_id / tenant_id |
Allowed | Immutable unless system_rls_context() |
| Connection pooling | Context could persist | Reset on connect + each request |
CustomPolicy validation |
DDL blocklist | Also rejects whitespace-only + DML keywords |
Quick migration checklist
- Replace ad-hoc
set_rls_context("user_id", …)withsystem_rls_context(). - If you used session-based tenants, enable
ALLOW_SESSION_TENANTand addTENANT_MEMBERSHIP_VALIDATOR. - Register custom context keys with
REGISTERED_CONTEXT_KEYSif you use connection pooling. - Turn on production hardening:
REQUIRE_CONTEXT,AUDIT_LOG,STRICT_MIGRATE_RLS. - Add
python manage.py audit_rlsto your CI/deploy pipeline.
Full step-by-step guide: Migrating from 0.4.x
Updated documentation
The docs site at django-rls.com now has versioned documentation:
- 1.0 (current) — default, includes new guides for Configuration, Context management, and Migrating from 0.4
- 0.4 — archived docs for apps still on the previous line
- Next — in-development docs (not indexed for search engines)
Local testing docs now reflect the real PostgreSQL workflow (docker compose + make test).
Install / upgrade
pip install django-rls==1.0.0
Or in requirements.txt / pyproject.toml:
django-rls>=1.0.0,<2.0.0
Staying on 0.4.x? Pin explicitly:
pip install "django-rls>=0.4.1,<1.0.0"
Docs for 0.4 remain at Introduction | Django RLS ( Introduction | Django RLS ).
Links
• Documentation: https://django-rls.com
• PyPI: Client Challenge
• GitHub: GitHub - kdpisda/django-rls: Row Level Security for Django · GitHub
• Changelog: django-rls/CHANGELOG.md at main · kdpisda/django-rls · GitHub
• Security policy: django-rls/.github/SECURITY.md at main · kdpisda/django-rls · GitHub
We want your feedback
If you hit migration issues, have questions about DJANGO_RLS settings, or want to share how you’re using RLS in production — reply here or open an issue on GitHub. Reports of edge cases around connection pooling, Celery workers, or multi-tenant session handling are especially welcome.
Thanks for using django-rls.
— Kuldeep