User Submitted Posts <= 20260113 - Incorrect Authorization to Unauthenticated Category Restriction Bypass via 'user-submitted-category' Parameter
Description
The User Submitted Posts – Enable Users to Submit Posts from the Front End plugin for WordPress is vulnerable to Incorrect Authorization in all versions up to, and including, 20260113. This is due to the `usp_get_submitted_category()` function accepting user-submitted category IDs from the POST body without validating them against the admin-configured allowed categories stored in `usp_options['categories']`. This makes it possible for unauthenticated attackers to assign submitted posts to arbitrary categories, including restricted ones, by crafting a direct POST request with manipulated `user-submitted-category[]` values, bypassing the frontend category restrictions.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=20260113What Changed in the Fix
Changes introduced in v20260217
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-2126 - User Submitted Posts Category Restriction Bypass ## 1. Vulnerability Summary The **User Submitted Posts** plugin (<= 20260113) contains an incorrect authorization vulnerability in the way it handles post category assignments during frontend submissions.…
Show full research plan
Exploitation Research Plan: CVE-2026-2126 - User Submitted Posts Category Restriction Bypass
1. Vulnerability Summary
The User Submitted Posts plugin (<= 20260113) contains an incorrect authorization vulnerability in the way it handles post category assignments during frontend submissions. While the plugin allows administrators to define a set of "allowed categories" for user submissions (stored in usp_options['categories']), the function responsible for retrieving the user's choice, usp_get_submitted_category(), fails to validate the submitted category IDs against this allowed list.
An unauthenticated attacker can manipulate the user-submitted-category[] POST parameter to assign their submission to any existing category on the WordPress site, bypassing the administrator's intended restrictions.
2. Attack Vector Analysis
- Endpoint: Any frontend page containing the
[user-submitted-posts]shortcode, or a direct POST request to the site's home/index URL (since the plugin processes submissions on theinitorparse_requesthook). - Vulnerable Parameter:
user-submitted-category[](POST body). - Authentication: Unauthenticated (Default configuration allows guest submissions).
- Preconditions:
- The plugin must be active.
- At least one "Private" or "Restricted" category must exist that the admin did not intend for public use.
- (Optional but common) The "Post Category" field is enabled in USP settings.
3. Code Flow
- Entry Point: A visitor submits the USP form. The plugin typically hooks into
initvialibrary/core-functions.php(referenced inuser-submitted-posts.php). - Submission Detection: The plugin checks for a specific POST parameter (often
usp-titleor a hidden trigger) to identify a submission attempt. - Data Retrieval: The processing logic calls
usp_get_submitted_category(). - The Vulnerable Sink: Inside
usp_get_submitted_category()(located inuser-submitted-posts.phporlibrary/core-functions.php):- It reads
$_POST['user-submitted-category']. - It performs basic sanitization (like
intval). - Vulnerability: It returns these IDs directly to the post creation logic without checking if the IDs exist within the
allowedarray found inget_option('usp_options')['categories'].
- It reads
- Post Creation: The returned category IDs are passed into
wp_insert_post()orwp_set_post_categories(), successfully assigning the post to the attacker-chosen category.
4. Nonce Acquisition Strategy
Based on the plugin architecture and readme.txt:
- The plugin emphasizes "anti-spam security" via challenge questions or Google reCAPTCHA rather than standard WordPress nonces for the submission itself, as it is designed for unauthenticated users.
- However, if a nonce is present, it is likely enqueued via
wp_localize_scriptinlibrary/enqueue-scripts.php.
Strategy:
- Create a page with the shortcode
[user-submitted-posts]. - Navigate to the page.
- Check for a localized JavaScript object. The common key for this plugin is
usp_vars. - Run in
browser_eval:window.usp_vars?.nonce. - If no nonce is found in the JS, check the HTML for a hidden field:
document.querySelector('input[name="usp-nonce"]')?.value.
5. Exploitation Strategy
The goal is to submit a post assigned to a category that is not in the allowed list.
Step 1: Discover Category IDs
Identify the ID of a restricted category (e.g., "Uncategorized" or a custom "Private" category).
Step 2: Form Submission Request
Send a POST request to the WordPress root or the page containing the form.
HTTP Request Template:
POST / HTTP/1.1
Host: target.local
Content-Type: application/x-www-form-urlencoded
user-submitted-name=Attacker
user-submitted-title=Bypass+Test
user-submitted-content=This+post+should+be+in+a+restricted+category.
user-submitted-category[]=TARGET_CATEGORY_ID
usp-nonce=NONCE_VALUE (if found)
usp_verify_default=1 (Often used as a form submission trigger)
6. Test Data Setup
- Create Categories:
- Create a "Public" category:
wp term create category "Public"(Note ID, e.g., 2). - Create a "Restricted" category:
wp term create category "Restricted"(Note ID, e.g., 3).
- Create a "Public" category:
- Configure Plugin:
- Set USP to allow only the "Public" category (ID 2).
wp option patch insert usp_options categories "2"- Ensure "Post Category" field is enabled:
wp option patch insert usp_options usp_category "show"
- Create Submission Page:
wp post create --post_type=page --post_title="Submit" --post_status=publish --post_content="[user-submitted-posts]"
- Enable Guest Submissions:
- Ensure
usp_options['logged_in_users']is not set to require login.
- Ensure
7. Expected Results
- The HTTP response should indicate success (e.g., a redirect or a success message like "Success! Thank you for your submission.").
- A new post should be created in the database.
- The
post_categoryor associated terms for this new post should include the Restricted category ID (ID 3), even though only ID 2 was allowed in settings.
8. Verification Steps
- Check Post Terms via WP-CLI:
# Get the ID of the latest post LAST_POST_ID=$(wp post list --post_type=post --posts_per_page=1 --field=ID --orderby=date) # List the categories assigned to that post wp post term list $LAST_POST_ID category --fields=name,term_id - Verify Bypass:
- If the output shows the "Restricted" category ID, the bypass is confirmed.
9. Alternative Approaches
- Multiple Categories: Attempt to pass an array to
user-submitted-category[]containing both an allowed ID and a restricted ID to see if validation is partial. - Hidden Inputs: If the form is configured to not show the category selector, the attacker can still append
user-submitted-category[]to the POST body, as the server-side codeusp_get_submitted_category()will still look for it. - Default Category Fallback: If the plugin has a "Default Category" setting, verify if providing an invalid or non-existent ID in the POST request triggers a fallback or if it allows assigning the post to no category (potentially hiding it from standard feeds).
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.