PostgreSQL Patched 52 Flaws. Update the Clients Too
PostgreSQL 18.7, 17.12, 16.16, 15.20, and 14.25 fix 52 vulnerabilities. Patch the server, pg_dump, and reindex where the notes say to.
By Muhammad Saif and Aashan Khan · Techtribe co-founders
On November 12, 2026, the PostgreSQL Global Development Group released an update to every supported major version: 18.7, 17.12, 16.16, 15.20, and 14.25, and it shipped the second release candidate of PostgreSQL 19. The announcement states the scope in one sentence. This release fixes 52 security vulnerabilities and over 140 bugs reported over the last several months.
Fifty-two CVEs in one minor cycle is a lot of surface for an application that treats the database as a library call. Most generated apps do treat it that way. The connection string is in an environment variable, the SQL was written by an agent, and nobody on the team can say which minor version answered the last query. This note is the work after the announcement: which flaws change what you run, which tools have to move with the server, and which follow-up the new binaries do not do for you.
Row-level security mistakes in a Supabase project are a different failure, covered in RLS mistakes in AI-built apps. A migration that drops a column because an agent got impatient is covered in generated database migrations. This post is the November patch level.
What "52 vulnerabilities" is made of
The project lists the CVEs on the announcement, each with the versions it affects. You do not need to memorize fifty-two identifiers to decide whether to upgrade. You need the classes, because the classes tell you which binary and which follow-up.
The largest class is memory safety and type confusion that the project scores as arbitrary code execution. Help Net Security's readout of the batch says thirty-two of the fifty-two CVEs carry a CVSS of 8.8, the highest score in the set, and that the lowest, a bypass of the EXECUTE privilege on cast functions, scores 3.1. The 8.8s cluster in places generated apps actually use: PL/Perl and PL/Tcl, text search, parallel query, logical replication, dblink, and statistics import. A type-confusion bug is the server treating a value as the wrong type and then executing what that misread allows. It is not a theoretical parser issue if an extension, a replication connection, or a text-search query runs on the same database as your users.
A second class is SQL and command injection in the client tools, not in the server process your app speaks to. pg_dump could be injected through a not-null constraint name. The tar-format restore script did not block psql command injection. reindexdb mishandled quoting of index names. If another user of the database can create and name objects, those names are input to the tools you run as a trusted role. Updating the server image and leaving last year's pg_dump on a laptop preserves the bug on the laptop. The laptop is often the place an agent, or a founder, runs the backup.
A third class is authorization logic that was wrong even when memory was fine. INSERT ... ON CONFLICT could read or modify rows despite an auto-updatable view's WHERE clause. A related fix covers reading rows despite row security policies. DROP OWNED could remove restrictive row security policies from tables the role does not own. security_barrier views could expose hidden values through indirect expressions. These are the bugs that line up with an app whose "security" is a view or a policy an agent wrote once. The policy can be correct as SQL and still be bypassed by a server bug until you are on the fixed minor. After you are on the fixed minor, a policy that was never the right policy is still wrong. The upgrade does not review your RLS.
A fourth class is file and format handling around operations people think of as admin chores. dblink and subscriptions could append to arbitrary files. pg_basebackup could treat backup-manifest content as a format string. pg_restore could execute code because a non-plain archive was not validated. vacuumdb --missing-stats-only could let a database owner run code as the user who invoked vacuumdb. Admin tools are remote code execution waiting for a name, a manifest, or an archive if the tool trusts the database more than the operator does.
The announcement is the list. The security news archive is the index. Individual CVE pages, such as the write-up for CVE-2026-120152 (pg_show_all_settings() disclosing memory, fixed in 18.7, 17.12, and 16.16, and not present before 16), are where you confirm a version you are actually on. Do not stop at a blog's summary if you are deciding whether 15.x was affected by one item. The project page for that CVE says so. Use the summary to decide that you are upgrading, and the CVE page when a host claims you are already safe.
The follow-up the package manager will not run
Installing the new binaries closes the code paths. Several bug fixes still need a human, or a scheduled job, after the process has restarted on the new version. Help Net Security's account of the release notes is the checklist to keep next to the upgrade window.
GIN indexes you have reason to suspect are corrupt should be reindexed. So should pg_trgm GiST indexes that use gist_trgm_ops, which is the opclass behind a lot of "search this column like a user typed it" features in generated apps. B-tree indexes on bpchar columns declared without a length should be reindexed too. A table that starts throwing "missing chunk number" errors needs REINDEX TABLE, not a restart. These are not optional hygiene if the notes name them. A minor upgrade that leaves a corrupt index in place has patched the binary and kept the damage.
Incremental backups need a new base. If you take incrementals, take a new full backup after the upgrade and base later incrementals on that full. The reason in the coverage is blunt: several of the fixed bugs could produce corrupt backups. An incremental chain whose base was taken by the old binary is a chain you should not trust for the next restore drill. A backup you have never restored is still just a file. The restore drill is the subject of recovering an AI-built app after a bad deploy. The new full backup is the input that drill needs after this particular upgrade.
Extensions deserve a look after the server moves. Several of the code-execution bugs live in PL/Perl, PL/Tcl, and text-search dictionaries. If you do not use those languages, you are not in that path. If an agent enabled plpgsql only, do not confuse that with "no procedural language," but do not invent a Perl patch either. pgcrypto, pg_trgm, dblink, and anything in shared_preload_libraries should be names you can say out loud. An extension the agent added to make a demo search box work is part of the attack surface of this release if it is pg_trgm.
Statistics import and logical replication show up in the CVE list as well. If you load stats as part of a restore, or you replicate between a primary on the old minor and a subscriber you already upgraded, read the version notes for that CVE before you mix them. Mixed versions during a rolling upgrade are normal. Mixed versions across a bug that was type confusion in replication are how the rolling upgrade becomes the incident.
PostgreSQL 14 is finished
Version 14.25 is the final release of PostgreSQL 14. It receives the fixes in this batch, and then it receives nothing. No further security releases, no further bug fixes. A server that stays on 14 after this week is a server that will miss the next CVE on purpose, because the branch is over.
That is a migration project, not a apt upgrade. Moving a major version can break extensions, change planner choices, and require a dump and restore or a tool like pg_upgrade that you have not rehearsed. Generated apps are bad at this because the schema was never written down as a decision. It accumulated. The way to move is still the ordinary one: a restore onto the new major, the application's test suite against that restore, and a cutover when the suite is the real one and not a screenshot. How generated migrations go wrong is the hazard during the move. An agent that "helps" by rewriting types in the same window as the major upgrade will give you two incidents.
PostgreSQL 19's second release candidate shipped in the same drop, with general availability planned for November 19, 2026. A release candidate is not the version to put a customer's data on unless you are testing the upgrade. It is the version to install beside production, run your queries, and see what the planner and your extensions do. Teams that skip RC testing discover the breakage on GA day, which is the day everyone else is upgrading too.
Phoronix's report on the release noted that this batch lands while the project has been dealing with a surge of AI-assisted bug reports, and that PostgreSQL 19 had been running weeks behind schedule under that load. That is a schedule fact about the project. It is not a reason to skip 18.7. It is a reason to expect the next cycle to be large as well, and to have a way to learn your version in an hour rather than discovering it during the incident. The research side of that surge, models finding bugs in stacks that used to take months, is in what the 90-hour vulnerability study actually measured.
Hosted Postgres, containers, and the version you think you run
The binary that matters is the one that accepted your app's last connection. It is often not the binary you would get from a local postgres --version.
Supabase, Amazon RDS, Google Cloud SQL, Azure Database, Neon, Crunchy, and a Docker image your compose file pinned last spring can each be on a different minor. A provider "based on PostgreSQL 15" might be 15.8. The fix for this batch on the 15 line is 15.20. The gap between those two numbers is the vulnerabilities. Open the provider's version page, or run SELECT version(); from the role your app uses, and write the string down. A screenshot of the project dashboard from March is not a version.
Some hosts apply minor upgrades on a maintenance window you do not control, and some wait for you to click. Know which one you bought. If the host has already moved you to 15.20, you still own the reindex and the new full backup, because those are data operations, not package operations. If the host has not moved you, a support ticket that says "please patch" is the change. An application deploy is not.
Client tools drift the same way. A developer laptop with Homebrew, a CI image with a Debian postgresql-client from the base layer, and a GUI such as pgAdmin or a hosted backup runner can each speak to the server with an old pg_dump. The injection bugs in dump and restore care about the client. Make the CI image bump a deliberate commit. Make the laptop part of the same checklist. An agent that shells out to pg_dump uses whatever is on PATH. That is the client you just decided to trust.
Connection poolers do not need a CVE of their own to matter here. PgBouncer, Supabase's pooler, and an ORM that caches prepared statements will keep talking to the new server, which is what you want. They will not reindex. They will not tell you that the backup sidecar is still on 14. Put the sidecar on the list.
If the database is inside a generated app's Docker Compose and the image tag is postgres:15, you are tracking a moving tag only if you pull. If the tag was resolved when the agent first ran docker compose up and the server has been that container ever since, you are on whatever minor existed that day. Pin the minor, pull the fixed image, and accept a restart. A container that has been up for four months is not "basically 15.20" because the major matches.
What an application owner does this week
The order is version, window, binaries, follow-up, proof.
Identify every database that holds user data, including the one everyone calls staging if it was copied from production. Record the version string and the client version that takes backups. If any of them are on 14, the patch to 14.25 is the emergency, and the upgrade off 14 is the project you schedule immediately after. Staying on 14.25 through the next CVE is a choice to run unsupported software.
Take a backup with a client you have updated, and confirm it restores somewhere that is not the production disk. Then install the fixed server minor and the fixed client tools in the same change. Mixing a new server with an old pg_dump leaves the injection bugs in the tool you will use if the upgrade goes badly.
After the new server is up, reindex the indexes the notes name if you have them. Search the schema for gin, for gist_trgm_ops, and for character or bpchar columns with no length. Reindex is heavier than a package install. Run it when you can lock the index, or use the project's concurrent form where the index type allows it, and watch for the "missing chunk number" error the notes call out. If that error appears, REINDEX TABLE is the documented response, not another restart.
Take a new full backup from the patched server and point the incremental chain at it. Keep the pre-upgrade backup until you have restored the new one once. Two backups, one of them rehearsed, is the minimum. One backup taken by the old client and never restored is how this upgrade becomes a data loss with a green deploy log.
Then look at the authorization bugs as a prompt to test your own policies, not as a substitute for that test. With two roles, try the view and the row security policy your app relies on. A bypass that was a server bug should fail closed on the new minor. A bypass that is your policy will still succeed, and you want to see that now. The Supabase-shaped version of that test is in the RLS mistakes post.
Restart the application after the database restarts, or confirm the pool reconnected. Generated apps often cache a connection at boot and then surface a wall of 500s that look like an application bug. They are the pool talking to a server that went away for the upgrade. That is a success condition you should expect, not a reason to roll the database back.
What to check before you call the upgrade done
- Write down
SELECT version();for production and for any copy that has real user data. The string needs to be 18.7, 17.12, 16.16, 15.20, 14.25, or a newer minor on a supported major. "15" is not a match. - If the string starts with 14, you are on the last release that branch will ever have. Schedule the move to a supported major. Do not let an agent rewrite the schema in the same weekend unless a person is reviewing the SQL.
- Update
pg_dump,pg_restore,reindexdb, andvacuumdbeverywhere they run: CI, laptops, backup sidecars, GUI tools. - Reindex suspect GIN indexes,
gist_trgm_opsindexes, and lengthlessbpcharB-trees. If you see "missing chunk number,"REINDEX TABLE. - Take a new full backup with the new client and restore it once. Point incrementals at that full.
- Retry the row security and view checks with a second role. The server patch does not prove your policy.
- If you cannot see the version because a host hides it, open a ticket and keep the reply. A dashboard logo is not a patch level.
If you cannot produce the version string, you are not ready to say the 52 are behind you. The announcement is not the install.
If this is your app, send the repo.
A 30-minute scope call. We read what is live, name what is dangerous, and quote a fixed scope.
How Techtribe patches a generated app's database
We read the repo and the live database, record the version the app is actually talking to, and separate a minor upgrade from a major move off PostgreSQL 14. You get the client tools and the reindex list in writing, then a fixed price for the upgrade and the restore drill. We do not let an agent rewrite the schema in the same window and call that the patch.
If the schema is still the one the agent generated and the product needs a data model someone can operate, that scope is a Production MVP. A single version bump on a database you already understand is smaller. The scope call is 30 minutes with a founder, and it is where we say which you are in.
Bring the host, the version string, and whether pg_dump or a dashboard backup is how you restore. If you have never restored one, say that. It changes the order of the call.
The fixed scope for taking a generated app to production is a page per tool: Lovable, Bolt, v0, and Replit.
Questions
Which PostgreSQL versions fix the November 2026 vulnerabilities?
The PostgreSQL Global Development Group shipped 18.7, 17.12, 16.16, 15.20, and 14.25 on November 12, 2026, plus PostgreSQL 19 release candidate 2. Anything older on those major versions is behind this batch. 14.25 is the last release of PostgreSQL 14.
Is updating the server package enough?
No. Several of the fixes are in client tools. pg_dump had a SQL injection through not-null constraint names, its tar restore script could allow psql command injection, and reindexdb mishandled quoting of index names. Update the client binaries you use to dump, restore, and reindex, not only the server in production.
Do we have to reindex after installing the new binaries?
For some bugs, yes. GIN indexes you suspect are corrupt, pg_trgm GiST indexes that use gist_trgm_ops, and B-tree indexes on bpchar columns declared without a length should be reindexed. A table that throws a missing chunk number error needs REINDEX TABLE. If you use incremental backups, take a new full backup and base later incrementals on it.
What if the database is hosted and we cannot see the version?
Ask the host, or run a version query against the database your app uses. Supabase, RDS, Cloud SQL, and a container image can all lag the upstream release. A dashboard that says PostgreSQL is not a version. 14.25 being the final 14.x build means a host still on 14 needs a move, not another minor.