← All scenarios

Scenario · Security & Access

Overprivileged application role

A sandboxed PostgreSQL incident — investigate with your own tools, submit a fix, and get deterministic Detect / Fix / Trap scoring.

L3 · 10–15 min · runs locally in Docker

Launch

Start this scenario

Boot it in a real PostgreSQL sandbox and investigate with psql, EXPLAIN and pg_stat_statements.

ride postgres start stage-10/02-overprivileged-application-role

Part of these paths

Show the postmortem & investigation hints spoilers
Overprivileged application role
Type: incident simulation · Topic: Security & Access · Level: L3 · Duration: 10–15 min
Launch: ride postgres start stage-10/02-overprivileged-application-role

POSTMORTEM (root cause · how it was found · the fix · lesson)
Root cause: `app_user` had been granted dangerous cluster attributes — CREATEDB and
CREATEROLE — on top of the table privileges it actually needs. The application
worked, so nothing alerted, but the role was a standing security liability: a
compromised app connection could create databases and roles.

How it was found: pg_roles showed rolcreatedb / rolcreaterole set on app_user;
information_schema.role_table_grants showed the legitimate, minimal table grants it
should keep.

The fix (least-privilege): strip the attributes, keep the grants:
  ALTER ROLE app_user NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION;

Lesson: application roles must be least-privilege — no SUPERUSER / CREATEDB /
CREATEROLE / REPLICATION, only the object privileges the app uses. Never "fix"
access incidents by granting superuser, and don't over-correct by revoking the
privileges the app legitimately needs (that just trades a security bug for an outage).

INVESTIGATION HINTS (the staged path to diagnose and fix)
1. The app works, but a security review flagged app_user. Inspect its cluster attributes: SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolreplication FROM pg_roles WHERE rolname = 'app_user'; An application role should hold none of those.
2. app_user has CREATEDB and CREATEROLE it never needs. Check what table access it actually uses (information_schema.role_table_grants) so you can trim attributes without breaking the app.
3. Strip the excess attributes while keeping the table grants: ALTER ROLE app_user NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION; Don't grant superuser, and don't revoke the app's SELECT/INSERT/UPDATE on app_orders (that breaks production).