2026-08-15 · view entry permalink →
GeoServer: an unauthenticated SQL injection in the jsonArrayContains filter is being exploited with no CVE and no patch, and NCSC-CH has put it in front of Swiss operators
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 matters for triage; this is mass reconnaissance against an unpatchable exposure, not yet a wave of confirmed intrusions, and the window to reduce exposure is still open.
Two things make this worse than its missing CVE suggests. There is no identifier, so a purely CVE-driven patch process, scanner feed or SBOM pipeline will not surface it at all, the same blind spot this pipeline recorded on the Metabase zero-day six days ago. And there is no fix: NCSC-CH's advisory states plainly that no patch is currently available and tells operators to identify exposed instances, restrict public access and monitor for exploitation (NCSC-CH, 2026-08-14). 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.
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.
The flaw this pipeline described as exploited with no vendor fix (where the only advice available was exposure reduction) 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 scopes 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 (GeoTools, 2026-08-15). No CVE identifier exists yet, so this remains invisible to a purely CVE-driven patch process.
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). GeoTools describes the flaw as a regression of CVE-2023-25158 confined to this single function.
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 disagree, and the disagreement is worth stating plainly rather than resolving. GeoTools says no mitigation is available, and specifically that the CVE-2023-25158 mitigation of enabling prepared statements and disabling encode functions is not effective (GeoTools, 2026-08-15). 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 this week has one source telling them a switch closes the path and the vendor telling them it does not. 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.