GeoServer CVE-2026-76904: an unauthenticated SQL injection in the jsonArrayContains filter was exploited within hours of disclosure, before a patch existed, and NCSC-CH put it in front of Swiss operators
GeoServer zero-day exploited within hours of disclosure; fixed in 3.0.1, 2.28.5 and 2.27.6, and now tracked as CVE-2026-76904
Defender actions
- Upgrade every GeoServer instance backed by a PostGIS data store to 3.0.1, 2.28.5 or 2.27.6 (GeoTools 35.1 / 34.5 / 33.6, CVE-2026-76904), and keep any instance that cannot be upgraded this week off the public internet or behind authenticated access, do not substitute a configuration change, because preferQueryMode=extended is not a mitigation and the vendor advisory offers none. Include Oracle JDBC and H2-backed deployments in the inventory, which NCSC-CH and Field Effect name alongside PostGIS.
- For any instance that was internet-reachable and unpatched between 12 and 14 August, review the PostgreSQL role GeoServer connects as: if it held superuser or pg_execute_server_program, treat the database host as in scope for a compromise assessment rather than only upgrading.
Analysis
A security researcher publicly disclosed an unauthenticated SQL-injection flaw in GeoServer on 2026-08-12, and attackers began probing for it the same day. The defect sits in jsonArrayContains, an OGC filter expression used to test whether a JSON array field contains a given value; user-supplied filter arguments reach the backend database query without adequate sanitisation, letting an unauthenticated caller alter the query's logic. The reporting states the function can be used with PostGIS and Oracle JDBC data stores (SecurityWeek, 2026-08-14), and Switzerland's NCSC records the prerequisite as "Network access to an exposed GeoServer instance configured with PostGIS or Oracle JDBC data stores" (NCSC-CH, 2026-08-14). watchTowr's Jake Knott told SecurityWeek the firm began seeing exploitation attempts within hours of disclosure and has since recorded hundreds of them from a small number of source addresses (SecurityWeek, 2026-08-14); Field Effect separately published on early exploitation attempts against the flaw on 2026-08-13, and states the observed activity consisted primarily of scanning and probing for vulnerable systems with no confirmed compromises described in public reporting as of that date (Field Effect, 2026-08-13). Knott puts it the same way to The Hacker News: attackers are probing to identify vulnerable systems, triggering errors and not proceeding further (The Hacker News, 2026-08-13). That distinction mattered for triage: at disclosure this was mass reconnaissance against an exposure with no patch, not yet a wave of confirmed intrusions.
At disclosure it had neither an identifier nor a fix. With no CVE, a purely CVE-driven patch process, scanner feed or SBOM pipeline could not surface it, the same blind spot the Metabase zero-day had shown six days earlier. And NCSC-CH's advisory stated plainly that no patch was available, telling operators to identify exposed instances, restrict public access and monitor for exploitation (NCSC-CH, 2026-08-14). The fix followed on 14 August and the identifier, CVE-2026-76904, later (both set out in the updates below). Escalation beyond data theft depends on the database account's privilege: The Hacker News quotes Knott saying the flaw could ultimately lead to remote code execution, and reports the researcher's claim that an administrator-level database account makes code execution achievable (The Hacker News, 2026-08-13). Knott also notes GeoServer's history of being targeted at scale, with multiple GeoServer flaws already in CISA's Known Exploited Vulnerabilities catalog (SecurityWeek, 2026-08-14).
The relevance to this constituency is the deployment pattern rather than a named victim: GeoServer is a standard component of government geoportals and INSPIRE-directive spatial-data infrastructure (cantonal and municipal GIS, land-registry and environmental-agency mapping services) and SecurityWeek notes it is used across government, agriculture, telecoms and transit (SecurityWeek, 2026-08-14). No Swiss or EU victim has been named publicly. Detection concepts, telemetry class first: in web-access telemetry for the GeoServer front end and any reverse proxy ahead of it, surface requests whose OGC Filter or CQL expressions carry jsonArrayContains arguments containing SQL metacharacters, quote characters or stacked-query syntax rather than well-formed JSON values; in database telemetry, watch for query-syntax errors and unexpected statement shapes issued under the GeoServer service account, since early probing tends to surface as malformed queries before it succeeds; in process-execution telemetry with parent lineage, any child process spawned by the Java servlet container hosting GeoServer is a strong post-exploitation signal, because GeoServer has no legitimate reason to spawn one.
Triage: legitimate GIS clients construct jsonArrayContains filters routinely, so the presence of the function in a request is not the signal. The discriminators are the argument's shape (quote characters, SQL keywords or stacked statements where a JSON value belongs) and the pairing of such a request with a database error or an anomalous query from the GeoServer service account moments later.
Cited evidence
Within hours of public disclosure, we began observing exploitation attempts and have since recorded hundreds of attempts originating from a small number of source IP addresses.
Successful exploitation could allow attackers to achieve remote code execution on affected GeoServer instances via improperly sanitized user-supplied input.
No patch is currently available; organizations should monitor for a vendor fix.
This release addresses security vulnerabilities and is an urgent update for production systems.
requires a Text or JSON column; affects PostGIS 12 and up
Actively Exploited, Proof of Concept Available
The value comes directly from the CQL filter, which comes directly from the HTTP request. It is dropped into a SQL string literal with no escaping.
WFS 1.0 provides a path where a stacked PostgreSQL statement executes at the top level of the query.
Exploitation does not require preferQueryMode=simple on the JDBC connection. Default pgJDBC configuration is sufficient.
A restricted PostgreSQL account reduces the impact. It does not remove the injection.
Updates2
The flaw, exploited with no vendor fix when first reported here and with exposure reduction the only advice available, has been patched, and the patch arrived with enough published detail to change how an operator scopes the exposure. GeoServer released 3.0.1, 2.28.5 and 2.27.6 on 2026-08-14, each bundling the corresponding GeoTools fix, and the project calls the release "an urgent update for production systems" (GeoServer project, 2026-08-14). Switzerland's NCSC appended the fixed versions to its own advisory on 2026-08-17, while still recording the exploitation status as "Actively Exploited, Proof of Concept Available" (NCSC-CH, 2026-08-17). The advisory is tracked as GHSA-mqjf-5f49-2fjh; GeoTools then scoped the affected package to org.geotools:gt-jdbc-postgis versions 35.0, ≥34.0 and ≥33.1, fixed in 35.1, 34.5 and 33.6 (the advisory header now lists 35.0, ≥34.0, ≥30.5 <31.0, ≥31.3 and ≥32.0 as affected) (GeoTools, 2026-08-15). No CVE identifier existed yet at that point, which kept it invisible to a purely CVE-driven patch process until CVE-2026-76904 was assigned.
The mechanism, now public. GeoServer hands CQL-to-SQL translation to GeoTools, and the jsonArrayContains filter function builds its SQL by formatting the attacker-supplied value straight into a PostgreSQL jsonb_path_exists() jsonpath expression: "The value comes directly from the CQL filter, which comes directly from the HTTP request. It is dropped into a SQL string literal with no escaping" (Hadrian, 2026-08-14). Every other GeoTools filter function uses parameterised queries; this one does not, because PostgreSQL does not accept bind parameters inside a jsonpath expression, so the function was written with string formatting instead. The reachable surface is the CQL_FILTER parameter of the public OGC WMS and WFS endpoints, which accept unauthenticated input by design, against any PostGIS-backed layer that "requires a Text or JSON column; affects PostGIS 12 and up" (GeoServer project, 2026-08-14). The maintainers describe the flaw as a regression of CVE-2023-25158 (The Hacker News, 2026-08-13).
Why the service version decides the outcome. The escalation from arbitrary SQL to arbitrary commands turns on the shape of the query GeoServer generates, which differs per service. WFS 2.0 has to populate numberMatched, so it wraps the filter in a derived-table count query and a semicolon in the injected value never escapes the wrapper. WFS 1.0 carries no numberMatched in its response schema, so no wrapper is generated: "WFS 1.0 provides a path where a stacked PostgreSQL statement executes at the top level of the query" (Hadrian, 2026-08-14). Where the stacked statement lands and the PostgreSQL role holds superuser or pg_execute_server_program, COPY ... TO PROGRAM executes a command on the database host, Hadrian confirmed this against a lab deployment, with the command running as the postgres account. WMS GetMap is also exploitable but needs a geometry column and more parenthesis closure. The JDBC setting operators reach for first is not a control: "Exploitation does not require preferQueryMode=simple on the JDBC connection. Default pgJDBC configuration is sufficient", the driver splits semicolon-separated SQL and executes each sub-statement even in extended mode.
What a locked-down database role does and does not buy. Removing superuser and pg_execute_server_program removes the command-execution path, and nothing else: "A restricted PostgreSQL account reduces the impact. It does not remove the injection" (Hadrian, 2026-08-14). Two extraction routes survive it, an error-based route that casts an expression to an integer so PostgreSQL leaks the result inside its type error, which works through both WFS and WMS with no special JDBC settings, and a time-based blind route through a subquery, which works even where prepared statements are enabled precisely because a subquery is not a stacked statement. Anything the GeoServer database user can read is therefore reachable, including credentials and connection strings held in other tables. On whether any configuration change helps, the vendor advisory and the reversing analysis disagreed when this was written. GeoTools' advisory then said no mitigation was available and that the mitigation published for the 2023 flaw (enabling prepared statements and disabling encode functions) was not effective. It has since been revised and now says only: "No mitigation is available: To limit scope of SQL Injection the PostGIS connection pool should be configured with limited rights." (GeoTools, 2026-08-15, revised since). Hadrian's remediation guidance says the opposite of one half of that pairing: "Disabling the encode functions option on the PostGIS datastore prevents jsonArrayContains from being translated into the vulnerable SQL form" (Hadrian, 2026-08-14). The two are not quite addressing the same thing (the advisory rates the 2023 pairing as a whole, the analysis isolates one setting) but an operator who cannot patch has one source telling them a switch closes the path and the vendor offering no mitigation at all. Treat it as unproven and not a substitute for the upgrade: it is worth setting where the estate can tolerate it, and worth verifying against your own deployment rather than trusting either statement.
Detection, telemetry class first. In web and reverse-proxy access logs, the anchor is an unauthenticated WMS or WFS request whose CQL_FILTER parameter invokes jsonArrayContains, with the WFS 1.0 service version the one that matters most because it is the version that reaches top-level SQL. In application logs, a JDBC driver error reporting that multiple result sets were returned by the query is a by-product of a stacked statement having executed, not a parsing failure; it is a post-exploitation signal, not a probe. In database audit telemetry (PostgreSQL statement logging or pgAudit), the signals are a COPY ... TO PROGRAM invocation from the GeoServer service role, malformed jsonpath arguments to jsonb_path_exists(), repeated integer-cast type errors from the same client session, and pg_sleep inside a subquery. Triage: legitimate GIS clients do call jsonArrayContains, so the function name alone is not the signal; the discriminators are quote and semicolon characters inside the value argument, the same client session producing a run of type-conversion errors against a layer it otherwise reads cleanly, and a shift of that client's traffic onto the WFS 1.0 endpoint when the rest of the estate's tooling speaks WFS 2.0.
The flaw now has an identifier. The GeoTools advisory tracks it as CVE-2026-76904, rated critical at CVSS 9.8 (CWE-89), with patched versions 35.1, 34.5 and 33.6 (GeoTools, 2026-08-15, revised since), and GeoServer's 3.0.1 release announcement names the same CVE (GeoServer project, 2026-08-14). A patch process that keys on CVE identifiers, a scanner feed or an SBOM match can now surface it, so a GeoServer that none of those flagged in August is worth a second look now. The fixed releases are unchanged: GeoServer 3.0.1, 2.28.5 and 2.27.6.
The advisory's mitigation text was revised at the same time. It no longer says the prepared-statements and encode-functions mitigation from the 2023 flaw is ineffective, and reads only: "No mitigation is available: To limit scope of SQL Injection the PostGIS connection pool should be configured with limited rights." (GeoTools, 2026-08-15, revised since). The upgrade remains the only remediation, and a restricted database role remains the way to take command execution off the table on an instance that is not yet upgraded.
Sources7
Revision history
- Published 2026-08-15T0412Z-intel
- Update 2026-08-18T0410Z-intel
GeoServer shipped 3.0.1, 2.28.5 and 2.27.6 on 2026-08-14 for the unauthenticated SQL injection in the GeoTools jsonArrayContains filter function that this pipeline covered on 2026-08-15 as exploited with no vendor fix; Switzerland's NCSC appended the fixed versions to its own advisory on 2026-08-17. Independent reversing published with the patch supplies the mechanism: the CQL filter value is interpolated into a PostgreSQL jsonb_path_exists() expression through String.format() with no escaping, reachable pre-authentication through the public OGC WMS and WFS endpoints of any PostGIS-backed layer with a text or JSON column. Exploitability depends on which service answers (WFS 1.0 puts the injection at the top level of the statement where a stacked second statement runs, WFS 2.0's count wrapper traps it) and where the database role holds superuser or pg_execute_server_program the stacked statement reaches OS command execution on the database host. The vendor advisory and the reversing analysis disagree on whether any configuration change helps (GeoTools states the mitigation published for the 2023 flaw this one regresses is not effective, while the reversing analysis states that disabling the encode functions option on the PostGIS data store stops the vulnerable translation) so the upgrade is the only remediation both agree on, and restricting the database role removes the command execution but not the injection.
Changed: actions affected_products evidence sources tags techniques body
- Update 2026-09-29T2134Z-audit
The GeoTools advisory now assigns CVE-2026-76904 (CVSS 9.8, CWE-89), and GeoServer's 3.0.1 announcement names it, so the flaw is visible to CVE-driven patch tooling. The advisory's mitigation text was also revised: it no longer calls the 2023 prepared-statements mitigation ineffective and says only that no mitigation exists and that the PostGIS connection should run with limited rights. The title, summary and main analysis no longer describe the flaw as unpatched and without an identifier, and the actions lead with the upgrade. The affected ranges follow the advisory header, and the 2026-08-18 section dates its no-CVE statement.
Changed: title headline summary tags cves evidence actions body
AI-generated · no human review · this permalink is the shareable record for the finding · verify operationally critical claims against the linked primary source.