CVE-2026-75529 Overview
CVE-2026-75529 is a stored cross-site scripting (XSS) vulnerability in Pandora, the analysis platform from pandora-analysis. The flaw resides in the PDF download functionality exposed by the /task-download/<task_id>/.../pdf endpoint. The endpoint validated uploaded files using content-based detection but returned them via Flask's send_file(task.file.path) without specifying a MIME type or forcing an attachment disposition. Attackers can submit polyglot files that pass PDF validation while carrying a filename or extension that causes Flask to return an active MIME type. A victim following the download link executes attacker-controlled script in the Pandora application context. This vulnerability is classified under [CWE-79].
Critical Impact
Attacker-supplied script executes in a victim's browser session, enabling access to Pandora application data and actions performed under the victim's identity.
Affected Products
- Pandora (pandora-analysis) prior to commit 668ec65a93cee327e3d925da2698849c9e65625a
- Web interface component website/web/__init__.py
- PDF download endpoint /task-download/<task_id>/.../pdf
Discovery Timeline
- 2026-08-17 - CVE-2026-75529 published to NVD
- 2026-08-18 - Last updated in NVD database
Technical Details for CVE-2026-75529
Vulnerability Analysis
The Pandora PDF download route validates that a stored file is a PDF using content-based file-type detection. After validation, the route returns the file with Flask's send_file() helper and supplies only the filesystem path. Flask then infers the response Content-Type from the file's name or extension rather than the validated content type. This mismatch between content validation and response headers creates the stored XSS condition.
A polyglot file whose bytes satisfy Pandora's PDF detection can carry an extension such as .html or .svg. When the browser receives the response, it renders the file according to the inferred MIME type. Because the response is served inline from the Pandora origin, any script inside the polyglot executes in the security context of the Pandora application.
Root Cause
The root cause is missing explicit response headers on send_file(). Without an explicit mimetype argument and without as_attachment=True, Flask relies on the filename to determine both Content-Type and Content-Disposition. Trusting attacker-controlled filenames for header derivation breaks the security boundary established by content-based validation.
Attack Vector
An unauthenticated attacker submits a specially crafted polyglot file to Pandora for analysis. The file passes PDF content detection while retaining a filename that maps to an active MIME type. A victim with access to the submitted analysis clicks the PDF download link. The browser renders the response inline, executing attacker-controlled script and exposing the victim's session data to the attacker.
# NOTE: need to also return a PDF of office doc.
if not task.file.is_pdf:
raise Unsupported('PDF not available')
- return send_file(task.file.path)
+ return send_file(task.file.path, mimetype='application/pdf',
+ as_attachment=True, download_name=f'{task.uuid}.pdf')
if source == 'txt' and flask_login.current_user.role.can(Action.download_text):
if not task.file.text:
Source: GitHub Commit Details. The patch forces Content-Type: application/pdf, sets as_attachment=True to add Content-Disposition: attachment, and rewrites the filename to {task.uuid}.pdf.
Detection Methods for CVE-2026-75529
Indicators of Compromise
- Submitted analysis tasks containing files with mismatched extensions such as .html, .svg, .xml, or .js while passing PDF validation
- HTTP responses from /task-download/<task_id>/.../pdf returning Content-Type values other than application/pdf
- Download responses lacking Content-Disposition: attachment from the Pandora web tier
- Unexpected outbound requests from analyst browsers to attacker-controlled domains following PDF review
Detection Strategies
- Inspect Pandora web logs for /task-download/ requests followed by anomalous browser navigation or new authenticated actions from the same session
- Compare uploaded filename extensions against detected file types recorded by Pandora, alerting on divergence
- Deploy a Content Security Policy (CSP) in report-only mode to log inline script execution served from the Pandora origin
Monitoring Recommendations
- Log every response returned by the PDF download route and alert when Content-Type is not application/pdf
- Track task submissions whose filenames contain HTML, SVG, or XML extensions and correlate with subsequent download activity
- Monitor analyst account behavior for session actions following a PDF download event
How to Mitigate CVE-2026-75529
Immediate Actions Required
- Update Pandora to a revision that includes commit 668ec65a93cee327e3d925da2698849c9e65625a or later
- Restrict access to the Pandora analysis interface to trusted internal networks until patched
- Review recent task submissions for polyglot files with non-PDF extensions and quarantine matches
Patch Information
The upstream fix is committed at pandora-analysis/pandora commit 668ec65. The patch amends website/web/__init__.py so the PDF download route calls send_file() with mimetype='application/pdf', as_attachment=True, and download_name=f'{task.uuid}.pdf'. These three changes eliminate filename-driven MIME inference and force browser-side download behavior.
Workarounds
- Front Pandora with a reverse proxy that rewrites downloaded file responses to Content-Type: application/pdf and appends Content-Disposition: attachment
- Enforce a strict Content Security Policy that disables inline script and object execution on the Pandora origin
- Normalize uploaded filenames server-side to a fixed .pdf extension before storage or delivery
# Example nginx override enforcing safe headers on the PDF route
location ~ ^/task-download/[^/]+/.*/pdf$ {
proxy_pass http://pandora_backend;
proxy_hide_header Content-Type;
proxy_hide_header Content-Disposition;
add_header Content-Type "application/pdf" always;
add_header Content-Disposition "attachment" always;
add_header X-Content-Type-Options "nosniff" always;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

