CVE-2026-97469 Overview
CVE-2026-97469 affects PostgreSQL Anonymizer, an extension that masks sensitive data in PostgreSQL databases. The vulnerability lets an unprivileged masked user repeatedly invoke the anon.hash() function and collect (seed, hash_output) pairs. An attacker can then perform an offline brute-force attack to recover the salt used by the masking engine. The flaw stems from the ability to call a RESTRICTED function from within a sub-select, bypassing the intended access control. The maintainers resolved the issue in PostgreSQL Anonymizer 3.2.3 and later. The weakness is classified under CWE-328: Use of Weak Hash.
Critical Impact
Recovery of the masking salt enables an attacker to reverse hashed values across the dataset, undermining the pseudonymization guarantees of the extension.
Affected Products
- PostgreSQL Anonymizer versions prior to 3.2.3
- Deployments relying on anon.hash() for pseudonymization with a shared secret salt
- Multi-tenant PostgreSQL environments exposing masked roles to untrusted analysts
Discovery Timeline
- 2026-09-25 - CVE-2026-97469 published to the National Vulnerability Database
- 2026-09-29 - Last updated in NVD database
Technical Details for CVE-2026-97469
Vulnerability Analysis
PostgreSQL Anonymizer provides the anon.hash() function to deterministically pseudonymize values using a configured salt. The function is declared RESTRICTED, which should prevent masked roles from invoking it directly. The access control check fails when the call is wrapped inside a sub-select, allowing a masked role to execute the function at will.
By supplying arbitrary seeds and observing the returned hash values, an attacker builds a large corpus of plaintext-to-hash pairs. The attacker then runs an offline dictionary or brute-force search against the hash function to recover the server-wide salt. Once the salt is known, every previously masked hash becomes reversible using the same procedure.
Root Cause
The root cause is incomplete enforcement of the RESTRICTED function policy inside planner-rewritten sub-queries combined with the use of a weak keyed hash construction [CWE-328]. The salt acts as the only secret, and the function provides an oracle that leaks enough information to recover it offline.
Attack Vector
Exploitation requires an authenticated low-privilege database role that has been assigned a masking policy. The attacker issues SQL queries that call anon.hash(seed) from inside a sub-select, iterating over chosen seeds. Collected pairs are exfiltrated and processed on attacker-controlled hardware to recover the salt without further interaction with the target.
No verified public proof-of-concept is referenced in the advisory. Technical discussion is available in the PostgreSQL Anonymizer GitLab Issue #685.
Detection Methods for CVE-2026-97469
Indicators of Compromise
- Repeated SQL statements from a single masked role invoking anon.hash() within sub-select constructs
- Unusually high query volume from analyst or reporting roles that only require aggregate access
- Query patterns iterating sequentially or dictionary-style through seed values
Detection Strategies
- Enable pg_stat_statements and alert on high-frequency calls to anon.hash originating from non-administrative roles
- Review PostgreSQL audit logs (pgaudit) for sub-select wrappers around restricted anonymization functions
- Baseline normal query behavior for masked roles and flag statistical deviations in function call counts
Monitoring Recommendations
- Forward PostgreSQL audit logs to a centralized analytics platform for long-term retention and correlation
- Monitor outbound data transfer volumes from database clients that hold masked role credentials
- Track changes to anon schema function definitions and extension versions across environments
How to Mitigate CVE-2026-97469
Immediate Actions Required
- Upgrade PostgreSQL Anonymizer to version 3.2.3 or later on all database instances
- Rotate the anonymization salt after patching to invalidate any salt an attacker may have already recovered
- Audit masked roles and revoke EXECUTE privileges on anon.hash() where not required
Patch Information
The maintainers resolved CVE-2026-97469 in PostgreSQL Anonymizer 3.2.3. The fix enforces the RESTRICTED function policy for calls placed inside sub-selects, blocking the oracle. Refer to the GitLab Issue #685 for release details and commit references.
Workarounds
- Restrict access to the anon schema and explicitly REVOKE EXECUTE ON FUNCTION anon.hash(text) FROM PUBLIC until upgrade is complete
- Replace deterministic hashing with randomized masking functions where re-identification resistance is required
- Limit masked role connectivity to trusted application tiers using pg_hba.conf and network ACLs
# Configuration example
# Revoke direct execution of the vulnerable function from masked roles
psql -U postgres -d yourdb -c "REVOKE EXECUTE ON FUNCTION anon.hash(text) FROM PUBLIC;"
# Verify installed extension version
psql -U postgres -d yourdb -c "SELECT extname, extversion FROM pg_extension WHERE extname = 'anon';"
# Upgrade the extension after installing package >= 3.2.3
psql -U postgres -d yourdb -c "ALTER EXTENSION anon UPDATE TO '3.2.3';"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

