SEC.PRIV.ROLE_CREATEROLE — The account may create roles
- Category: security
- Severity: medium
- Level: 0
- Confidence: deterministic
- Downtime class: none — the finding is about an account, not about a statement
- Stability: stable
- Suites: audit
- Applies to: PostgreSQL 18
What changed in PostgreSQL 16, and what did not
Most write-ups describe CREATEROLE as a full escalation: alter any non-superuser role, grant any
membership, therefore give yourself anything. That was true, and it is not what happens now.
Measured on PostgreSQL 18, as a role holding CREATEROLE and nothing else:
| Attempt | Result |
|---|---|
| create a new role | allowed |
| alter a role it did not create | refused — only roles with the CREATEROLE attribute and the ADMIN option on role "…" may alter this role |
grant itself pg_read_all_data | refused — same shape |
| alter a role it did create | allowed (it holds ADMIN on what it creates) |
So the account cannot take privileges it does not already hold. What it can do is create login accounts with passwords of its choosing and administer them — access that lives outside your deployment process and survives a password rotation on the account everybody knows about.
Bad
ALTER ROLE app CREATEROLE;
Good
ALTER ROLE app NOCREATEROLE;
If something in your deployment genuinely creates roles — a tenant-per-role design, a provisioning job — give that job its own role and leave the application's alone.
Related
If the account is also a superuser, SQLens reports SEC.PRIV.ROLE_SUPERUSER and stays quiet here: a
superuser holds this attribute by definition, and two findings about the same account would bury the
one that matters.