On this page · 6 sections
Any team running a psqlODBC release from 08.01.0102 through 18.00.0004 must move to 18.00.0005, and the most urgent cases are applications that let external input decide how many parameters a statement binds. The psqlODBC release announcement describes CVE-2026-109448, a heap memory corruption issue with a CVSS 3.1 base score of 5.9 (Medium), and states that all users should upgrade. The defect sits in how the driver stores a count, so exposure depends on how your statements are shaped, not only on which driver version is installed.
What the driver got wrong #
According to the announcement, psqlODBC kept the number of bound parameters on a statement in a signed 16-bit field. When an application bound too many parameters on one statement, the driver wrote zeros outside the memory that holds the parameter bindings. The announcement says the application could crash, or it could keep running with corrupted memory. Those are the two outcomes the source names, and they are why this is a security fix as well as a functional one.
The announcement gives one concrete exposure pattern: an application that builds an IN (?, ?, ...) list from user-supplied values, where the user effectively controls how many placeholders are created. The source presents this as its example of exposure. It does not enumerate other application types, so check your own code for the same pattern rather than assuming a particular application is safe.
The threshold wording needs care. The announcement's heading describes the flaw as occurring when binding more than 32767 parameters, while the body says that the driver misbehaved when an application bound more than 32768 parameters. Both phrasings appear in the source. For migration purposes, the rule that matters is the one the fixed driver enforces: SQLBindParameter now rejects parameter numbers above 32767. Design your limits around that check.
The announcement credits Richard Kuesters with reporting the problem. It also refers to advisory GHSA-cmfx-rm3r-p2jr. That advisory is not reproduced here, so read it directly if you need the full technical detail before you brief a security team.
Who must migrate, and what else the release fixes #
Migrate every deployment that runs a version in the affected range. The announcement asks all users to upgrade, so the decision does not depend on whether a given service builds long lists today. Upgrading the whole fleet also picks up two bug fixes that the release lists separately, and both can matter for ordinary workloads.
The first concerns statements prepared on the server with 1000 or more parameters. The announcement says such statements could fail with errors such as type "timestam" does not exist. From parameter 1000 onward, the driver cut the type name that followed each parameter to fit a fixed-size buffer. If your application prepares statements of that size, this is a functional defect you will want fixed alongside the security issue.
The second concerns bytea parameters. The announcement says that since 18.00.0003, bytea parameters failed with "Type is invalid" when used through Microsoft's OLE DB Provider for ODBC (MSDASQL), for example from ADO. If your applications reach the driver through that path, test them after the upgrade. The announcement also notes that the Windows packages are now built with OpenSSL 3.5.9, which is a build change you should account for in any Windows host inventory.
The new behaviour in SQLBindParameter #
After the fix, SQLBindParameter rejects parameter numbers above 32767 and returns SQLSTATE 07009. The announcement explains the reason for the limit: SQLNumParams and SQL_DESC_COUNT are 16-bit values, so ODBC cannot report more than 32767 parameters. The driver is therefore enforcing a limit that the interface itself already imposes.
The announcement also states that no earlier release could run a statement with more than 32767 parameters. That is the basis for its claim that the change does not break any application that worked before. A statement that large was never a working case, so the new check removes a path that could only ever corrupt memory or fail.
The fixed driver still returns an error for those requests, so your application must handle it. The announcement does not describe how SQLSTATE 07009 surfaces in each client framework, so test that path explicitly in staging instead of assuming your framework will translate it into a sensible message.
Migration steps #
The announcement's primary guidance is to upgrade the driver. It also gives an interim option for teams that cannot upgrade right away: limit the number of parameters the application builds from external input, or pass long value lists as a single array parameter. The steps below follow that guidance. The staging, rollback, and testing work is this article's recommendation for any driver change, not something the announcement states.
- Inventory every application and service that uses psqlODBC, and record the installed driver version on each host.
- Find each code path where the number of bound parameters depends on user-supplied values, such as an
IN (?, ?, ...)list built from a request body or a form. - Upgrade to psqlODBC 18.00.0005 in a staging environment first. The announcement says Windows installers and merge modules for x86, x64 and ARM64 are available from the PostgreSQL download site and from the GitHub release page.
- If an upgrade has to wait, cap the number of parameters built from external input. The announcement suggests passing long value lists as one array parameter, for example
= ANY(?). The announcement does not show how that array is bound through ODBC, so verify the form in your own client stack before relying on it. - Handle SQLSTATE 07009 so that an over-limit request produces a controlled error, not a crash or a silent continuation.
- Run regression tests that cover prepared statements with 1000 or more parameters, and any bytea paths that go through MSDASQL.
- Roll the upgraded driver out to production, and keep the previous installer available so that you can roll back if a regression appears.
Before: one placeholder per supplied value #
The old way creates one placeholder for each value the caller supplies. The number of placeholders follows the size of the input, so a large request can push a single statement past the 32767 limit that the fixed driver enforces, and past the 16-bit count that the vulnerable driver mishandled. The snippet is illustrative and has not been executed. The ... marks the rest of the placeholder list.
-- Old way: one placeholder per user-supplied value
SELECT id, status, updated_at
FROM orders
WHERE customer_id IN (?, ?, ?, ...);
After: one array parameter #
The new way sends the whole list as a single array parameter, so the bind count stays at one regardless of how many values the caller sends. The announcement offers this form as an interim option for long value lists when an upgrade is not yet possible. It changes the query shape, so test it against your ODBC client stack before you depend on it. This snippet is also illustrative and has not been executed.
-- Interim form: one array parameter, fixed bind count
SELECT id, status, updated_at
FROM orders
WHERE customer_id = ANY(?);
Warning
The main pitfall is assuming that the upgrade alone makes the application safe. After the fix, the driver refuses parameter numbers above 32767 with SQLSTATE 07009. Code that builds placeholder lists from user input will receive errors when a request is large. If the application does not handle that error, the request will fail instead of corrupting memory, and the service must be ready for that outcome. Change the query shape and add error handling together, and do not treat the new error as something that can be ignored.
The flow below follows the sequence the announcement supports. The upgrade comes first, and the interim limit or array form applies only while the upgrade is delayed.
Verification checklist #
Use this checklist before you close the migration ticket. Confirm each item in the environment where the driver actually runs, not only in the build pipeline or the package manifest.
- Every host reports psqlODBC 18.00.0005, and no host remains on a version from 08.01.0102 through 18.00.0004.
- No code path builds a placeholder list whose length is controlled by untrusted input without an enforced size limit.
- Where the interim array form is used, it has been tested in staging with your ODBC client stack.
- A deliberately oversized request returns a controlled error rather than crashing, and the error handling recognises SQLSTATE 07009.
- Prepared statements with 1000 or more parameters run correctly, if your application uses them.
- bytea parameters work through MSDASQL, if your application reaches the driver through ADO or OLE DB.
- Applications return the same results on the upgraded driver in staging as they did before.
- Any new driver problem is reported to the psqlODBC issue tracker or the pgsql-odbc mailing list, as the announcement requests.
The driver fix is straightforward, but the migration is not finished until the application stops depending on unbounded parameter lists. Upgrade to 18.00.0005, bound or restructure any parameter pattern that depends on external input, and handle SQLSTATE 07009 as a normal application error. Those steps close the exposure that CVE-2026-109448 describes.
Sources
- PostgreSQL: psqlODBC 18.00.0005 released with security fix for CVE-2026-109448 postgresql.org · Oct 14, 2026
Also consulted
- PostgreSQL: PostgreSQL 19 RC 1 Released! postgresql.org · Oct 15, 2026
- PostgreSQL: PgBouncer 1.26.1 released - Fixes three CVEs postgresql.org · Oct 14, 2026
- PostgreSQL: Introducing pglifecycle 2.0 beta postgresql.org · Oct 14, 2026
Edited and approved by Jarosław Krzemiński. Spotted a mistake? Report a correction or read the corrections policy.




Comments