← Security research PUBLISHED DISCLOSURE · CVE-2026-96450

Contributor stored XSS in a plugin shipped to 21,000+ WordPress sites

A default WordPress Contributor account could store script-bearing content through two pixfort Core data paths - the global Header builder and Portfolio Text metadata - that did not apply the sanitization boundary WordPress Core applies to ordinary post content. The content remained inert through administrator review and executed after publication, in an anonymous visitor’s browser. Fixed in version 4.3.3.

CVE published · Sources checked

Vulnerability analysis

Stored (persistent) cross-site scripting differs from the reflected variant in where the payload resides: it is saved server-side by the application and delivered to subsequent visitors as part of the site’s normal output, with no further attacker action required after the storage and publication steps. The account that stores it needs neither the publish_posts nor the unfiltered_html capability - a default WordPress Contributor account is sufficient.

The vector reflects that chain. The issue is network-reachable (AV:N) at low attack complexity (AC:L) and requires low privileges (PR:L) - the Contributor role, a role WordPress defines specifically for unprivileged users who submit content for review. User interaction is required (UI:R), and in the demonstrated chain it takes two distinct forms: an administrator publishes the Contributor-created content, and a visitor loads the affected front-end page. Scope is changed (S:C), the metric that carries the finding’s weight: the vulnerable component is the WordPress application, but the script executes inside the visitor’s browser, a separate security authority operating under the site’s origin and the visitor’s session context. Scored impacts are confidentiality low (C:L) and integrity low (I:L), with no availability impact (A:N).

Affected data paths

Both paths below are as documented in the submission evidence. The public CVE text summarizes the issue as Contributor-level XSS and does not enumerate them individually.

Path 1 - Global Header builder. A Contributor saved the test content in pixfort’s global Header builder as a draft. The content did not execute when an administrator reviewed it. After the administrator published the Header, the stored content executed in an anonymous browser session loading the homepage.

Path 2 - Portfolio Text metadata. A Contributor saved the test content in the Portfolio Text field, again as a draft, with the same review behavior: no execution during administrator review. After publication, the content executed in an anonymous browser session viewing the public Portfolio item.

The structural point common to both paths is the position of the publication gate. The WordPress editorial workflow treats administrator review as the control that makes a low-privilege role safe. In both paths the payload was inert in the review context and became active only in the front-end rendering context, which means the gate through which the content passed was not a context in which its behavior was observable.

Root cause

The submission included a negative control: equivalent content submitted through the ordinary WordPress post-content path was sanitized by WordPress Core’s KSES filtering, as expected for an account without unfiltered_html. The pixfort-specific fields did not enforce an equivalent boundary. The report attributes the gap to the division of responsibility between storage and rendering: pixfort Core stored Contributor-controlled data from its custom fields without the neutralization applied to core content, and Essentials - the rendering companion required for the demonstrated front-end execution - later rendered that stored data on the public site. The reported component is pixfort Core; Essentials 4.3.0 is named because it was the renderer in the validated configuration.

Test configuration and methodology

All validation was performed in an isolated synthetic Docker lab, with no production system and no client or customer data involved: WordPress 7.1, Pixfort Core 4.3.0, and Essentials 4.3.0. Three contexts were kept separate throughout - a Contributor session for storage, an Administrator session for the review-and-publication step, and an anonymous browser session for front-end verification - so that execution could be attributed to a specific context rather than inferred. Each path was exercised through the full sequence: save as draft, administrator review (no execution), publication, anonymous front-end load (execution).

The investigation was AI-assisted: the evidence record attributes the source and browser investigation and the exact 4.3.0 replay to gpt-daybreak-blue-latest at medium effort. Validation was confined to the configuration above and to Pixfort Core 4.3.0. The affected range - all versions before 4.3.3 - is as published in the advisory.

Severity assessment

The 5.4 base score reflects the two constraints in the chain - the low-privilege account requirement and the administrator-publication and visitor-interaction requirements - balanced against the scope change, under which code supplied by the least-trusted editorial role executes for unauthenticated visitors in the site’s origin. CISA’s SSVC assessment at publication (Sep 30, 2026) recorded exploitation as “none,” automatable as “no,” and technical impact as “partial,” a point-in-time exploitation status. Patchstack characterizes the issue as low severity and unlikely to be exploited; the CVSS record stands at 5.4 Medium, and that is the figure this page reports.

The finding’s research interest lies less in the score than in the mechanism: two independent custom data paths reproduced the same failure mode, in each case bypassing the review control not by defeating it but by remaining inert until the content crossed into the rendering context.

Remediation

Update pixfort Core to version 4.3.3 or later. That is the remediation in both the Patchstack advisory and the CVE record.

Public records