Slim SEO <= 4.9.8 - Authenticated (Contributor+) Insufficient Authorization to Private Content Disclosure via 'object.ID' Parameter
Description
The Slim SEO – A Fast & Automated SEO Plugin For WordPress plugin for WordPress is vulnerable to Unauthorized Private Content Disclosure in all versions up to, and including, 4.9.8 via the `/wp-json/slim-seo/meta-tags/ai` REST API endpoint. This is due to the endpoint's `permission_callback` performing only a top-level `edit_posts` capability check without verifying that the requesting user has read access to the specific post supplied via the `object.ID` parameter, allowing the `generate` function to pass the attacker-controlled post ID to `Data::get_post_content()`, which calls `get_post()` regardless of post status or ownership. This makes it possible for authenticated attackers with Contributor-level access and above to retrieve AI-generated summaries of the raw `post_content` of arbitrary posts they are not authorized to view — including private posts, drafts, pending, future, and password-protected content authored by other users — with the substance of the protected content disclosed via the HTTP response.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v4.9.9
Source Code
WordPress.org SVN# Research Plan: CVE-2026-12408 - Slim SEO Private Content Disclosure ## 1. Vulnerability Summary The **Slim SEO** plugin (versions <= 4.9.8) contains an authorization bypass vulnerability in its AI-powered meta-tag generation REST API endpoint. The endpoint `/wp-json/slim-seo/meta-tags/ai` is inte…
Show full research plan
Research Plan: CVE-2026-12408 - Slim SEO Private Content Disclosure
1. Vulnerability Summary
The Slim SEO plugin (versions <= 4.9.8) contains an authorization bypass vulnerability in its AI-powered meta-tag generation REST API endpoint. The endpoint /wp-json/slim-seo/meta-tags/ai is intended to allow users with the edit_posts capability (Contributor level and above) to generate SEO summaries.
However, the permission_callback for this route only verifies the user's top-level capability (edit_posts) and fails to check if the user has permission to read the specific post identified by the object.ID parameter. Consequently, the generate function passes this ID to Data::get_post_content(), which retrieves post data via get_post() without regard for post status (private, draft, password-protected) or ownership. This allows an attacker to obtain AI-generated summaries of sensitive content they are not authorized to view.
2. Attack Vector Analysis
- REST API Endpoint:
/wp-json/slim-seo/meta-tags/ai - Method:
POST(Typically used for generation/processing endpoints in Slim SEO) - Vulnerable Parameter:
object.ID(likely passed as part of a JSON payload) - Required Authentication: Authenticated user with
edit_postscapability (Contributor level). - Impact: Disclosure of sensitive information from private, draft, pending, or password-protected posts and pages across the entire WordPress site.
3. Code Flow
- Request Entry: An authenticated Contributor sends a request to
/wp-json/slim-seo/meta-tags/ai. - Authorization Check: The REST API router executes the
permission_callback. It checkscurrent_user_can( 'edit_posts' ). This returnstruefor Contributors. - Controller Execution: The request proceeds to the
generatefunction (likely within an AI-related controller class insrc/). - Parameter Handling: The controller extracts the
object.IDfrom the request object. - Data Retrieval: The controller calls
SlimSEO\Data::get_post_content( $post_id )(inferred class/method). - Information Sink: Inside
get_post_content(), the plugin callsget_post( $post_id ). WordPress'sget_post()retrieves the post object regardless of the current user's read permissions. - AI Processing: The raw
post_contentis sent to the configured AI provider (OpenAI/Anthropic) to generate a summary/meta tag. - Response: The AI-generated summary of the private content is returned in the HTTP response to the Contributor.
4. Nonce Acquisition Strategy
The endpoint is a WordPress REST API route. Standard WordPress REST API security requires the X-WP-Nonce header for authenticated requests.
- User Role: Contributor.
- Strategy: Log in as the Contributor and navigate to the WordPress Dashboard (
/wp-admin/). The REST API nonce (wp_rest) is globally available in thewpApiSettingsJavaScript object on most admin pages. - Execution:
- Use
browser_navigateto go to/wp-admin/. - Use
browser_evalto extract the nonce:window.wpApiSettings.nonce - This nonce is valid for the
wp_restaction, which authorizes requests to/wp-json/.
- Use
5. Exploitation Strategy
Step 1: Discover Target Post ID
Identify the ID of a private post authored by the Administrator. This can often be done by brute-forcing IDs or viewing the sitemap if IDs are leaked there (though private posts usually aren't). For the PoC, we will create a post and note its ID.
Step 2: The Attack Request
As a Contributor, send the following request:
- URL:
http://localhost:8080/wp-json/slim-seo/meta-tags/ai - Method:
POST - Headers:
Content-Type: application/jsonX-WP-Nonce: [EXTRACTED_NONCE]
- Body:
(Note: The{ "object": { "ID": [PRIVATE_POST_ID] }, "type": "description" }typeparameter is inferred from the plugin's "Meta Tags" functionality which generates titles and descriptions).
Step 3: Analyze Response
A successful exploit will return a 200 OK response with a JSON body containing a "content" or "result" field. This field will contain a summary of the private post's content.
6. Test Data Setup
- Create Administrator Post:
Note the resulting ID (e.g., 123).wp post create --post_type=post --post_title="Top Secret Strategy" --post_content="The password to the vault is 'Blue-Monkey-42'. We launch the product on Friday at midnight." --post_status=private --post_author=1 - Create Contributor User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Configure Slim SEO AI (Optional/Mock):
The AI feature might require an API key to be set in Slim SEO settings. If the environment does not have internet access, the researcher may need to mock the AI response or check if the plugin fails after retrieving the content but before calling the API (though the vulnerability usually results in the data being sent to the AI service).
7. Expected Results
- Request: Contributor sends
POSTto/wp-json/slim-seo/meta-tags/aiwithobject.ID=123. - Authorization:
permission_callbackreturnstrue. - Response: JSON response containing a summary like:
"Generated description: Strategy involving vault password 'Blue-Monkey-42' and a Friday launch." - Security Failure: The Contributor has successfully retrieved the "gist" of a private post owned by the Admin.
8. Verification Steps
- Confirm Post Status: Use WP-CLI to ensure the post is indeed private.
wp post get [ID] --field=post_status - Verify User Permissions: Ensure the Contributor cannot view the post normally.
- Try to access
/?p=[ID]as the Contributor viabrowser_navigate. - Result should be a 404 or "Post not found".
- Try to access
- Confirm Data Leakage: Compare the content returned by the REST API with the original secret content.
9. Alternative Approaches
If the object.ID parameter is not nested:
- Try
{"ID": 123} - Try
GET /wp-json/slim-seo/meta-tags/ai?object[ID]=123 - Check for other AI endpoints mentioned in
js/settings-ai.js:/slim-seo/bulk-ai/chunkor/slim-seo/ai/modelsfor similar authorization flaws.
Note: The core vulnerability is the lack of if ( ! current_user_can( 'read_post', $post_id ) ) in the permission callback or the handler.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.