Skip to content
Journal

Cybersecurity · Infrastructure Security

CVE-2026-44477: CloudNativePG's Superuser Escalation Bug

CVE-2026-44477 lets any database owner escalate to postgres superuser and run OS commands in CloudNativePG. Here is who is affected and how to patch.

Prathviraj Singh

Prathviraj Singh

5 min read

Title card for CVE-2026-44477 showing the attack chain: SET ROLE to pg_monitor, RESET ROLE to recover superuser, then COPY TO PROGRAM for OS command execution

Sponsored

Share

If you run PostgreSQL on Kubernetes through CloudNativePG, there’s a decent chance your metrics exporter is quietly giving away superuser. CVE-2026-44477 scores 9.4 on CVSS, and the path from “I have a normal app database role” to “I’m running shell commands as postgres inside your primary pod” takes about one scrape interval, which by default is 30 seconds.

What CVE-2026-44477 actually is

CloudNativePG’s built-in metrics exporter needs database access to report on things like connection counts, replication lag, and extension usage. To get that access without granting full superuser to a monitoring sidecar, it connects to Postgres over the pod-local Unix socket as postgres, then immediately runs SET ROLE pg_monitor to drop down to a limited monitoring role for the rest of the session.

That’s a reasonable design, and it would work, except for one detail: SET ROLE only changes current_role. It doesn’t touch session_user, which stays postgres for the life of the connection. Postgres exposes a command specifically to reverse a SET ROLE: RESET ROLE. Any SQL statement evaluated inside that scrape session, including one injected through a metric query, can call RESET ROLE and get full superuser back. From full superuser, COPY ... TO PROGRAM pipes query output through an arbitrary shell command, which means you’re no longer just reading database rows. You’re executing OS-level commands as the postgres user, inside the primary pod, on your production cluster.

Two ways to trigger it, per the GitHub Security Advisory:

  1. Schema shadowing with custom metric queries. If your monitoring config includes custom queries with unqualified identifiers (no explicit schema prefix), any user who owns a schema can plant an object with a matching name and get it picked up during the next scrape.
  2. The default configuration, with no customization at all. CloudNativePG ships a pg_extensions metric that calls current_database() without schema-qualifying it. That’s enough on its own. Any non-superuser database owner, including the app role most application connections already run as, can trigger the escalation without touching your monitoring config.

The second path is the one that should worry most teams, because it means “we didn’t customize our monitoring queries” isn’t a mitigation. It’s the default state that’s exposed.

Who’s actually exposed

Every CloudNativePG cluster on a version older than 1.28.3, or on 1.29.0 specifically, running with the default PodMonitor-based metrics collection enabled. Given that CloudNativePG has become close to the default choice for running Postgres on Kubernetes since Bitnami moved its free Postgres Helm chart behind a paywall in 2025, that’s a large population of production clusters, many of which enabled monitoring on day one and haven’t thought about the exporter’s privilege model since.

The attack requires only a low-privilege role and a connection to the database, both of which almost every application already has by design. This isn’t a bug that needs an insider with elevated access. It needs an application role, or anyone who’s compromised an application role, which is a much lower bar.

The fix, and why it’s a real fix

CloudNativePG 1.28.3 and 1.29.1, released May 8, 2026, don’t just patch the specific queries that leaked. They replace the underlying connection model. The exporter now authenticates as a dedicated cnpg_metrics_exporter role, scoped to only pg_monitor privileges, connecting through peer authentication configured in pg_ident.conf rather than logging in as postgres and demoting after the fact. There’s no superuser session sitting there for RESET ROLE to recover, because the exporter never holds superuser to begin with. Every built-in monitoring query also picked up explicit pg_catalog schema qualification, closing the shadowing path independently of the role change.

That’s the right shape of fix for this bug class: it removes the precondition (an escalatable session) rather than patching around individual exploitation techniques.

What to do this week

  • Check your CloudNativePG version. kubectl get pods -n <namespace> -o jsonpath='{.items[*].spec.containers[*].image}' against your operator deployment, or check your Helm chart’s app version. Anything before 1.28.3, or on 1.29.0, needs to move.
  • Upgrade to 1.28.3 or 1.29.1+. Standard operator upgrade path; CloudNativePG documents rolling upgrades that avoid a hard cutover on your primary. If your team hasn’t formalized how it handles rolling database changes generally, our guide to zero-downtime database migrations covers the same failover mechanics you’ll lean on here.
  • If you can’t upgrade today, disable PodMonitor-based metrics as a stopgap. You lose Prometheus visibility until you patch, which is a real cost, but it’s a smaller cost than an exposed superuser escalation path.
  • Audit who has database-owner-level access. This bug needs only an ordinary app role, so your existing least-privilege posture on application connections is your actual first line of defense, not an afterthought.

If you’re evaluating CloudNativePG or a similar operator as part of a broader move to Postgres on Kubernetes, this is worth folding into your evaluation checklist: ask any managed-Postgres-on-Kubernetes vendor exactly how their metrics collection authenticates, not just whether metrics are available.

The broader lesson

This bug existed because a sensible-sounding mitigation, SET ROLE after connecting as superuser, turned out to be reversible by design. SET ROLE was never meant to be a security boundary; Postgres’s own documentation is explicit that session_user is what persists. The fix that actually held up was removing the superuser connection entirely, not layering more role logic on top of it. When you’re reviewing your own infrastructure’s access patterns, the question worth asking isn’t “did we demote this connection,” it’s “can this connection get back what we demoted it from.” It’s the same question worth asking after any breach post-mortem, and it’s cheaper to ask it now than to work it out from what an incident actually costs after the fact.

Frequently asked questions

What is CVE-2026-44477?
It's a privilege escalation vulnerability in CloudNativePG, the CNCF operator for running PostgreSQL on Kubernetes. The built-in metrics exporter connects to Postgres as the postgres superuser and tries to demote itself with SET ROLE pg_monitor, but that only changes the current role for the session, not the underlying session_user. Any SQL evaluated during a metrics scrape can call RESET ROLE to get superuser back, then use COPY ... TO PROGRAM to run operating system commands as postgres inside the primary pod.
Who is affected by CVE-2026-44477?
Any CloudNativePG deployment on a version before 1.28.3 or 1.29.0 through before 1.29.1, running with the default monitoring configuration enabled. The default pg_extensions metric query alone is enough to trigger the vulnerable path, so you don't need any custom configuration to be exposed. An attacker needs only a low-privilege database role, such as the default app user most application connections already run as.
How do I fix CVE-2026-44477?
Upgrade to CloudNativePG 1.28.3 or 1.29.1 or later. The fix replaces the exporter's connection approach with a dedicated cnpg_metrics_exporter role that has only pg_monitor privileges and connects through peer authentication via pg_ident.conf, so there's no superuser session to escalate back to. It also adds explicit pg_catalog schema qualification to every built-in monitoring query, closing the second exploitation path (schema-shadowing with unqualified identifiers).
Is CVE-2026-44477 being actively exploited?
There's no public evidence of active, widespread exploitation the way there is for a KEV-listed browser or network-appliance CVE. That's not the same as low risk: the attack requires only a role most applications already use, completes within a single scrape interval (30 seconds by default), and the fix has been available since May 2026. A vulnerability without confirmed mass exploitation but with a trivial, well-documented attack path is exactly the kind that gets exploited quietly and discovered late.
Does disabling the metrics exporter fix the problem?
Yes, as a stopgap. If you can't upgrade immediately, disabling PodMonitor-based metrics collection removes the vulnerable code path entirely, at the cost of losing Prometheus visibility into your cluster until you patch. That's a reasonable short-term trade for a bug this severe, but it's a mitigation, not a fix. Upgrade to 1.28.3 or 1.29.1 as soon as you can and re-enable monitoring afterward.

Sources

Sponsored

Sponsored

Discussion

Join the conversation.

Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.

Sponsored