CVE-2026-94680 Stored XSS in The Post Grid via an unvalidated shortcode ID
Intrudify's autonomous pentesting engine discovered a stored cross-site scripting vulnerability in The Post Grid, affecting all versions up to and including 7.9.5. The shortcode accepts any existing post ID without checking that it refers to a grid, then prints around forty of that post's meta values into an inline <style> block and into HTML attributes with no escaping. A Contributor can close the style block and inject a live script tag.
Summary
The Post Grid renders configurable post grids through a shortcode. Intrudify's autonomous testing engine found that the shortcode's id attribute accepts any existing post ID, with no check that the referenced post is actually a grid. The plugin then loads every meta value on that post and feeds around forty of them into the rendered markup.
Because shortcode output is not passed through wp_kses, those values reach the browser verbatim. The grid-setting meta keys carry no leading underscore, so they are not protected meta, which means a Contributor can write them to their own post through the standard Custom Fields box.
Technical detail
Any post ID is accepted
In app/Controllers/ShortcodeController.php:
$scID = $atts['id'];
if ( $scID && ! is_null( get_post( $scID ) ) ) { // any existing post ID
$scMeta = get_post_meta( $scID ); // ALL meta of that post
$layout = ( isset( $scMeta['layout'][0] ) ? $scMeta['layout'][0] : 'layout1' );There is no get_post_type() check. The guard confirms only that a post with that ID exists, not that it is an rttpg grid, so the plugin will happily read its configuration out of an ordinary post that an attacker controls.
The sink
The meta flows into Fns::layoutStyle(), which concatenates it into a style block:
$css .= "<style type='text/css' media='all'>";
...
$primaryColor = ( isset( $scMeta['primary_color'][0] ) ? $scMeta['primary_color'][0] : null );
if ( $primaryColor ) {
$css .= 'color:' . $primaryColor . ';'; // no esc_attr, no sanitize_hex_color
}A value shaped to terminate the CSS block therefore escapes the style context entirely:
// written to the primary_color meta key via the Custom Fields box
red}</style><script>...</script>The </style> ends the CSS block and what follows is parsed as ordinary markup. Arbitrary JavaScript then runs in the viewer's browser.
Why the earlier fix does not cover this
The Post Grid patched a grid-creation XSS in 7.5.0 by adding Fns::sanitize() to the plugin's own grid-settings save path. That path is never reached here, because the meta is written directly to a normal post through WordPress core's Custom Fields box rather than through the plugin's settings screen.
This is the distinction worth noting for anyone reviewing similar patches. The earlier fix sanitises on input, at one specific entry point. The defect here is on the output side, and an input-side fix at a single controlled path cannot cover data that arrives some other way.
Verification
We confirmed that the page served to an unauthenticated visitor contained the unescaped breakout sequence with no escaped copies present, and that a real browser visiting the page executed the script.
As a negative control, setting the same meta key to an ordinary colour value renders color:#ff0000; correctly inside the style block with no breakout and nothing executing. The behaviour is attributable to the payload rather than to the shortcode in general.
Impact
The attacker needs only a Contributor account, which cannot publish and holds no unfiltered_html capability. Both steps of the attack sit inside that role's normal permissions: adding custom fields to a post requires edit_post, and placing a shortcode in the content is ordinary authoring.
The payload executes for the editor or administrator who previews the pending submission, which is a guaranteed step in the review workflow, and for every visitor once the post is published. We demonstrated script execution in the site origin. When the viewer is privileged, the usual consequences follow: session-scoped administrative actions, account creation, or plugin installation.
Remediation
Update The Post Grid to 7.9.6 or later.
For maintainers, there are two independent defects and fixing either breaks the chain. Check the post type before loading configuration from a shortcode-supplied ID, so only genuine grid posts can supply settings. And escape at the point of output, using sanitize_hex_color() for colour values and esc_attr() for the attribute contexts, rather than relying on values having been sanitised on the way in.
If you cannot update immediately, audit who holds Contributor accounts and treat pending-review posts as untrusted, since previewing a submission is enough to execute the payload.
The wider lesson
Two ordinary-looking decisions combine into this bug. The first is trusting an ID: the code verifies that a post exists but not that it is the right kind of post, so an attacker chooses which record supplies the configuration. The second is treating post meta as trusted because the plugin normally writes it, when in fact any meta key without a leading underscore is writable by anyone who can edit the post.
Neither is unusual on its own, which is why this kind of defect survives review. The generalisable check: wherever a shortcode accepts an ID and reads settings from it, confirm the post type, and assume unprotected meta is attacker-controlled regardless of which screen normally writes it.
Disclosure timeline
- 2026-09-18 Vulnerability identified and validated by Intrudify, reported via Patchstack
- 2026-09-23 Public disclosure · CVE-2026-94680 assigned
Questions
What is CVE-2026-94680?
CVE-2026-94680 is a stored cross-site scripting vulnerability in The Post Grid WordPress plugin, versions 7.9.5 and earlier. It was discovered autonomously by the Intrudify AI penetration testing engine. The shortcode accepts any existing post ID without checking the post type, then prints that post's meta into an inline style block with no escaping, letting a Contributor close the style block and inject a script tag.
Which versions of The Post Grid are affected?
All versions up to and including 7.9.5 are affected. This is a separate issue from the grid-creation XSS fixed in 7.5.0, which patched the plugin's own save path rather than the output path exploited here.
How do I fix CVE-2026-94680?
Update The Post Grid to 7.9.6 or later. If you cannot update immediately, audit who holds Contributor accounts and treat pending-review posts as untrusted, since previewing a submission is enough to execute the payload.