CVE-2026-15231: TaxoPress AI Preview Leaked Private Post-Derived Output
TaxoPress before 3.51.0 allowed Contributor-level users to reference private posts in the AI Preview workflow and receive output derived from posts they were not authorized to read.
CVE-2026-15231: TaxoPress AI Preview Leaked Private Post-Derived Output
Overview
TaxoPress versions before 3.51.0 contained a broken object-level authorization issue in the AI Preview workflow.
The interesting part of the bug was not the AI feature itself. The issue was the object reference passed into that feature. The AJAX request accepted a user-controlled preview_post value, then used the referenced post as input for preview generation before proving that the current user was allowed to read that post.
In the validated scenario, a Contributor referenced an Administrator-owned private post. WordPress would not normally allow that Contributor to read or edit the private post. However, the TaxoPress AI Preview workflow still processed it and returned preview output derived from the private content.
The issue is tracked as CVE-2026-15231 and WPVDB ID 5980ab15-bc6e-4298-9d0c-92c17217ec2c. The public advisory describes the issue as Contributor+ private post disclosure via IDOR and lists the fix in 3.51.0.
Affected Versions
- Product: TaxoPress WordPress Plugin
- Plugin slug:
simple-tags - Affected versions:
< 3.51.0 - Validated vulnerable version: 3.50.0
- Fixed version: 3.51.0
- Vulnerability type: IDOR / Missing Authorization
- CWE: CWE-639 — Authorization Bypass Through User-Controlled Key
- CVSS: 2.7 (Low)
- Required access: Contributor+
The Vulnerable Workflow
The vulnerable component was the AI Preview AJAX feature:
1
action=taxopress_ai_preview_feature
The request allowed the caller to provide a post identifier through:
1
preview_post=<post_id>
That value was security-sensitive because it selected the post used as input for preview generation.
A preview feature is easy to underestimate during review. It does not necessarily update a post, publish content, or change taxonomy terms. But it still reads application data and returns derived output. If the referenced object is private, draft, or owned by another user, the preview response can become an indirect disclosure channel.
The expected rule was simple: private posts should not influence responses returned to users who cannot read those posts.
Where the Trust Boundary Broke
The trust boundary was the transition from a Contributor-controlled preview_post value to server-side processing of the referenced post.
The request was made from an authenticated WordPress session and used a valid TaxoPress nonce. Those checks were not enough. They showed that the user could access the preview workflow, but they did not show that the user could read the specific post selected by preview_post.
The vulnerable shape looked like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
Contributor session
|
v
Valid TaxoPress preview nonce
|
v
preview_post=<private administrator post>
|
v
AI Preview processes referenced post
|
v
Preview output returned to Contributor
The missing question was:
1
Can the current user read this post before it is used as preview input?
In WordPress terms, the workflow needed an object-level authorization decision such as read_post for the final referenced post before generating the preview response.
How I Validated It
I tested the issue in a local WordPress lab using TaxoPress 3.50.0.
The validation used two roles:
- an Administrator who owned a private post;
- a Contributor who had access to the TaxoPress AI Preview workflow but did not have permission to read or edit the Administrator-owned private post.
The private post contained a unique marker so the preview response could be tied back to the protected content without ambiguity.
1
ZXCVBN_PRIVATE_TOKEN_2026
Before testing the TaxoPress endpoint, I verified the authorization boundary that should have applied:
- the referenced post was private;
- the post was owned by the Administrator;
- the Contributor did not have
read_postpermission for that post; - the Contributor did not have
edit_postpermission for that post.
Then I sent the AI Preview request as the Contributor while setting preview_post to the private Administrator-owned post.
The response returned success and included preview output derived from the private post. Runtime testing also showed that the Contributor received the same preview output as an Administrator when both referenced the same private post.
That comparison was important. It showed the workflow was not merely returning a generic response; it was processing the protected post and exposing derived data to a user who could not access the post directly.
Minimal Proof of Concept
The following request shape captures the vulnerable behavior from the Contributor session:
1
2
3
4
5
6
7
8
9
10
11
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: example.local
Content-Type: application/x-www-form-urlencoded
Cookie: <CONTRIBUTOR_COOKIE>
action=taxopress_ai_preview_feature
&preview_ai=suggest_local_terms
&preview_taxonomy=post_tag
&selected_autoterms=1
&preview_post=<PRIVATE_ADMIN_POST_ID>
&nonce=<VALID_TAXOPRESS_NONCE>
The important part is not the exact private marker used in the lab. The important part is the mismatch between the caller and the object being processed:
1
2
3
4
Caller: Contributor
Target post: Administrator-owned private post
Permission: Contributor lacks read_post and edit_post for the target
Observed: preview output derived from the private post is returned
A representative response contained the private marker in the returned preview content:
1
2
3
4
{
"status": "success",
"content": "...ZXCVBN_PRIVATE_TOKEN_2026..."
}
This demonstrated that the private post influenced the response returned to the Contributor.
Why the Existing Checks Were Not Enough
The endpoint was not simply open to the internet. The request used an authenticated Contributor session and a valid TaxoPress nonce.
Those checks answered narrower questions:
- Is the requester logged in?
- Is the request coming from a legitimate TaxoPress preview workflow?
They did not answer the object-level question that mattered:
1
May this user read the post selected by preview_post?
This distinction is the core of the vulnerability.
A feature-level permission can allow a user to open a preview UI. A nonce can reduce CSRF risk for that UI. Neither one automatically grants permission to use arbitrary post IDs as preview input.
For this endpoint, the authorization decision needed to happen after resolving the final preview_post target and before processing the post content into preview output.
Impact
The demonstrated impact was information disclosure from private post-derived preview output.
A Contributor could cause TaxoPress to process a private Administrator-owned post and return output generated from that post, despite lacking read_post and edit_post permission for the referenced object.
In the lab, the leaked value was a marker placed in the private post content. In a real site, the sensitivity depends on what private or draft content exists and how the AI Preview mode transforms that content into its response.
The supplied evidence supports confidentiality impact. It does not establish account takeover, code execution, or privilege escalation.
Patch and Defensive Takeaways
TaxoPress fixed the issue in 3.51.0.
The secure invariant is straightforward:
1
2
3
4
5
current user
+ requested preview operation
+ post selected by preview_post
-> read authorization check
-> preview generation only if allowed
For WordPress plugins, the key lesson is that preview and suggestion endpoints are still read paths. If they accept a post ID, they must authorize access to that post before using it as input.
A safer design would either derive the preview target from server-side state already scoped to the current user, or explicitly check whether the current user can read the supplied post before generating any output from it.
Recognizing This Pattern Elsewhere
This bug has a simple audit smell:
1
A low-privileged user controls an object ID used by a preview, suggestion, AI, search, or helper endpoint.
These endpoints often look harmless because they do not directly update the database. But if they read protected objects and return derived output, they still need object-level authorization.
When reviewing similar code, I would ask:
1
2
3
4
5
Who controls this post ID?
What post does it select?
Can the current user read that post?
Is authorization checked before the content is processed?
Does the response reveal exact or derived information from the selected object?
A useful runtime test is to create a private post with a unique marker, then compare the preview output for an authorized administrator and an unauthorized lower-privileged user. If both users receive the same marker-derived output, the preview feature is crossing an authorization boundary.
References
Responsible Disclosure Notice
This vulnerability has been publicly disclosed and fixed. The proof of concept is included for reproducibility, defensive validation, and security education.
Testing should be limited to systems you own or are explicitly authorized to assess. Site administrators should update TaxoPress to version 3.51.0 or later.