Aug 12, 2026·8 min read·4 visits
A stored XSS vulnerability in Jazzband tablib prior to 3.10.0 allows remote attackers to execute arbitrary JavaScript in browsers via crafted spreadsheet sheet names processed through HTML export pipelines.
CVE-2026-9318 is a stored cross-site scripting (XSS) vulnerability affecting Jazzband tablib versions prior to 3.10.0. The flaw is located in the HTML export functionality of multi-sheet Databook objects. Due to raw f-string interpolation, unsanitized sheet titles containing malicious script tags are rendered directly as HTML, allowing arbitrary client-side code execution in a victim's browser.
The library tablib is a format-agnostic tabular dataset manager in Python, maintained under the Jazzband organization. It is utilized to import, manipulate, and export data in multiple formats including XLSX, ODS, JSON, YAML, and HTML. Because applications rely on tablib to parse user-uploaded spreadsheets and convert them into other configurations, it exposes an entry point for processing untrusted structural metadata.
The stored cross-site scripting vulnerability, identified as CVE-2026-9318, occurs inside the HTML export pipeline for multi-sheet datasets, represented by Databook objects. When exporting a Databook to HTML, the library does not sanitize user-controlled worksheet names. If an attacker delivers a worksheet containing a script sequence in its metadata, the library parses and interpolates it directly into the generated output stream.
In typical production environments, the generated HTML page is subsequently rendered within a web application's administration console or reporting interface. This design flaw crosses a trust boundary, because worksheet metadata is assumed to contain only plain text layout labels. When a browser loads the exported document, it processes the script element under the hosting domain's security context.
This flaw is classified under CWE-79 (Improper Neutralization of Input During Web Page Generation). It presents a significant stored XSS risk because the spreadsheet does not execute payload strings on the backend, but stores the payload in a passive state until the HTML representation is triggered. Downstream integrations like django-import-export are also exposed to these data injection vectors if they permit spreadsheet upload and render sheet exports dynamically.
The architectural root cause of CVE-2026-9318 resides in the export_book method within the format handler module src/tablib/formats/_html.py. The class utilizes raw string concatenation and Python f-string formatting when constructing headings for individual worksheets. This pattern operates on the unsafe assumption that titles of sheets are sanitized before being assigned to Dataset objects.
During processing, the program executes a loop iterating over each dataset in the databook. The library assigns the value of dset.title to a local variable named title. If no sheet name exists, it assigns a default string representation. The flaw is exposed when the title is compiled into the document output stream: result += f'<{cls.BOOK_ENDINGS}>{title}</{cls.BOOK_ENDINGS}>\n'.
The default value of cls.BOOK_ENDINGS is the HTML tag 'h3'. Since the interpolation uses raw formatting rather than an HTML-safe encoder, any character sequence representing tags, such as <script>, is injected directly into the HTML payload as an operational tag rather than plain text. This directly leads to structural HTML injection.
Furthermore, spreadsheet parsers such as openpyxl or odfpyxl extract tab names straight from compressed XML structures inside modern office files. Because these parsers do not block special HTML characters in worksheet titles, the malicious elements flow into tablib without any validation boundaries. The absence of output sanitization at the terminal step is the core vulnerability.
To understand the vulnerable code path, observe the implementation of export_book in tablib versions preceding 3.10.0:
# Vulnerable version of export_book in src/tablib/formats/_html.py
def export_book(cls, databook):
result = ''
for i, dset in enumerate(databook._datasets):
title = dset.title if dset.title else f'Set {i}'
# Unsanitized concatenation of dset.title into output buffer
result += f'<{cls.BOOK_ENDINGS}>{title}</{cls.BOOK_ENDINGS}>\n'
result += dset.html
result += '\n'The implementation does not perform any escaping operations on title prior to evaluating the formatted string. To remediate this issue, the patch submitted in PR #668 implements safe node instantiation and serialization using Python's xml.etree.ElementTree module:
# Patched version of export_book in src/tablib/formats/_html.py
import xml.etree.ElementTree as ET
def export_book(cls, databook):
result = ''
for i, dset in enumerate(databook._datasets):
title = dset.title if dset.title else f'Set {i}'
# Safe generation using xml.etree.ElementTree
title_el = ET.Element(cls.BOOK_ENDINGS)
title_el.text = title
result += ET.tostring(title_el, method='html', encoding='unicode') + '\n'
result += dset.html
result += '\n'By leveraging ET.Element, the developer configures the DOM element using programmatic parameters where title is isolated strictly inside the .text property of the node. When ET.tostring is executed with the html serialization parameter, the standard library automatically encodes HTML-sensitive metacharacters. Characters such as < and > are translated to < and > respectively, which guarantees they are interpreted by the browser engine as plain text content rather than markup.
Analyzing the fix reveals that it successfully neutralizes the target injection channel without degrading performance or functionality. However, developers must ensure that elements surrounding dset.html do not introduce secondary cross-site scripting vulnerabilities elsewhere in the dataset body parsing pipeline.
Exploitation of CVE-2026-9318 requires two primary phases: an upload of a malicious spreadsheet file, and the execution of an HTML export that renders in an administrative or user context. The initial access vector is low-complexity and requires only standard file-upload privileges, which are commonly granted to end-users of business intelligence portals.
An attacker begins by preparing an ODS or XLSX spreadsheet document. Using standard programmatic tools or directly modifying the document's underlying XML, the attacker renames a sheet tab to include a client-side execution sequence. For example, setting the sheet name to <script>fetch("https://github.com/jazzband/tablib")</script> sets up the execution phase.
When the document is uploaded, the target application uses tablib to parse the workbook and populate a Databook object. The malicious sheet name is mapped directly into dset.title as a standard string. Once the administrative dashboard triggers an HTML render event, the code runs, producing a payload output that the browser compiles and executes.
Below is the sequence of events illustrating this attack lifecycle:
Prerequisites for a successful exploit include an active target rendering the HTML results without secondary escaping mechanisms. Many standard implementations display the raw HTML using template directives such as Django's |safe filter or Jinja2's |safe rendering. This bypasses the framework's native protection mechanisms, resulting in stored cross-site scripting.
The impact of this vulnerability depends on the privilege level of the victim user who views the HTML export. Because HTML pages generated by tablib are often administrative or audit reports, the typical victim is likely a privileged user or system administrator. Consequently, exploitation has a high probability of targeting management sessions.
When the payload executes in the victim's browser, it operates within the context of their authenticated session. If the application does not utilize secure cookie configurations, the script can extract session identifiers or authorization headers from document.cookie or LocalStorage. This allows the attacker to hijack active sessions and assume the victim's identity.
Beyond simple credential harvesting, the script can execute complex administrative actions. This includes initiating unauthorized API requests, modifying account configurations, or creating new administrative profiles within the target system. The scope of impact is classified as 'Changed' (S:C) because the browser sandbox exploitation breaks out of the context of the underlying library and affects the parent web application environment.
While CVSS assigns a medium score of 5.4, the relative danger is higher in enterprise environments where spreadsheet parsing is heavily automated. If the server application integrates other components with the compromised sheets, the integrity of downstream reporting workflows is broken.
The most effective mitigation is upgrading to tablib version 3.10.0 or higher, which completely patches the vulnerable interpolation code. To upgrade the library in standard environments, execute the pip update command or modify your requirement configuration: pip install --upgrade tablib>=3.10.0.
If upgrading immediately is not feasible, implement input sanitization rules at the entry point of the ingestion pipeline. Define a strict whitelist regex for worksheet names, allowing only alphanumeric characters, underscores, hyphens, and spaces. Ensure any title failing this check is sanitized or rejected before the databook object is passed to export format routines.
Deploy a strict Content Security Policy (CSP) header on target application domains. The header Content-Security-Policy: default-src 'self'; script-src 'self' prevents inline execution of scripts, neutralizing payloads delivered via the sheet title. Additionally, set the HttpOnly attribute on session cookies to prevent retrieval by XSS scripts.
Perform regular security audits of template rendering paths. Ensure that exported HTML strings are not marked as safe within templating engines unless they have been explicitly run through an HTML sanitization engine. This prevents developer-level output configuration from re-introducing structural injection issues.
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
tablib Jazzband | < 3.10.0 | 3.10.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 5.4 (Medium) |
| EPSS Score | 0.00181 |
| Impact | Arbitrary client-side script execution (Stored XSS) |
| Exploit Status | Proof of Concept (PoC) available |
| KEV Status | Not listed |
The software does not neutralize or incorrectly neutralizes user-controlled input before it is placed in output that is used as a web page that is served to other users.
CVE-2026-54917 is a critical path traversal and authorization bypass vulnerability affecting the S3 and Iceberg REST catalog gateways in SeaweedFS. By explicitly disabling canonical path cleaning in the gorilla/mux routing system, relative path segments such as '..' are allowed to bypass routing constraints and access control checks. When these paths are collapsed server-side by the backend filer, they resolve to folders outside the authorized bucket boundary, allowing unauthorized cross-bucket access.
An out-of-bounds read vulnerability in the SCTP SACK chunk parser of SIPSorcery leads to Denial of Service (DoS) or silent internal state corruption due to lack of boundary validation on incoming chunk elements.
An uncaught exception vulnerability exists in SIPSorcery's TurnServer component, where unauthenticated malformed UDP packets can crash the core UDP receive loop, resulting in a persistent Denial of Service.
A critical use-after-free vulnerability in Microsoft QUIC allows unauthenticated remote attackers to disclose sensitive system memory over the network. The vulnerability is caused by a race condition during rapid connection termination and asynchronous packet retransmission.
CVE-2026-62899 is a security feature bypass vulnerability in the Microsoft .NET runtime environment on non-Windows platforms. The flaw manifests as an HTTP Request/Response Smuggling vulnerability (CWE-444) within the managed implementation of the System.Net.HttpListener class. This allows unauthenticated remote attackers to desynchronize request boundaries when the backend .NET application is hosted behind an upstream reverse proxy.
CVE-2026-62901 is a high-severity Denial of Service (DoS) vulnerability in the Microsoft .NET ecosystem, specifically affecting the System.Net.WebSockets frame-processing engine and associated network transports. Under certain circumstances, a remote, unauthenticated attacker can exploit this vulnerability by sending malformed or specifically crafted WebSocket packets over the network, causing a targeted .NET application server to enter a tight infinite loop. This behavior results in 100% CPU utilization on the executing thread, starving application resources and leading to a complete Denial of Service.