CVE-2023-6991
Executive Summary
CVE-2023-6991 is a Server-Side Request Forgery (SSRF) vulnerability in the JSM file_get_contents() Shortcode WordPress plugin, affecting versions before 2.7.1. The plugin fails to validate a parameter passed to one of its shortcodes before making an HTTP request to the supplied URL. This allows authenticated users with contributor-level privileges or higher to force the WordPress server to make arbitrary HTTP requests to internal or external resources. The vulnerability is classified as a WordPress ecosystem issue, as it resides entirely within the plugin's code and does not involve the underlying web server (Apache/Nginx). The CVSS score is 0.0 in the NVD data, but based on the enriched intel and CWE-918, a more realistic vector is provided above, reflecting low confidentiality impact due to SSRF.
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. Users who installed the plugin from the repository are at risk. The supply chain risk is moderate, as the plugin is not a core dependency but can be used to pivot attacks within the WordPress environment. No known malicious packages or backdoors have been reported in the plugin's distribution chain.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – The vulnerability is exploitable over the network via crafted shortcode parameters.
- Attack Complexity (AC): Low (L) – No special conditions are required; the attacker simply submits a malicious shortcode.
- Privileges Required (PR): Low (L) – The attacker needs contributor-level access to the WordPress site.
- User Interaction (UI): None (N) – No user interaction is required beyond the attacker's actions.
- Scope (S): Changed (C) – The vulnerable component (plugin) impacts resources beyond its security scope (internal network).
- Confidentiality (C): Low (L) – Limited information disclosure via SSRF (e.g., internal service banners).
- Integrity (I): None (N) – No data modification is possible.
- Availability (A): None (N) – No denial of service impact.
Threat Level: Medium. While the CVSS base score is 4.3, the actual risk is elevated due to the potential for internal network reconnaissance and exploitation of other internal services.
Deep Dive & Mechanics
The JSM file_get_contents() Shortcode plugin provides a WordPress shortcode that fetches content from a remote URL using PHP's file_get_contents() function. The vulnerability arises because the plugin does not validate or sanitize the URL parameter passed to the shortcode. An attacker with contributor-level access can inject a shortcode like:
[jsm_file_get_contents url="http://169.254.169.254/latest/meta-data/"]
This causes the WordPress server to make an HTTP request to the specified URL. If the server is hosted in a cloud environment (e.g., AWS, GCP, Azure), the attacker can access cloud metadata endpoints, internal services, or other resources that are not intended to be exposed externally. The SSRF attack can be used for:
- Internal network scanning.
- Accessing cloud metadata (e.g., IAM credentials).
- Exploiting other internal services (e.g., Redis, Memcached, databases).
- Bypassing firewall restrictions.
The vulnerability is classified under CWE-918 (Server-Side Request Forgery). The plugin's code likely uses file_get_contents() directly on the user-supplied URL without any allowlist or blocklist validation.
Vulnerable vs. Patched Code
Vulnerable Code (version < 2.7.1):
function jsm_file_get_contents_shortcode($atts) {
$atts = shortcode_atts(array('url' => ''), $atts);
$url = $atts['url'];
// No validation of $url
$content = file_get_contents($url);
return $content;
}
add_shortcode('jsm_file_get_contents', 'jsm_file_get_contents_shortcode');
Patched Code (version 2.7.1):
function jsm_file_get_contents_shortcode($atts) {
$atts = shortcode_atts(array('url' => ''), $atts);
$url = $atts['url'];
// Validate URL
if (!filter_var($url, FILTER_VALIDATE_URL) || !preg_match('/^https?:\/\//i', $url)) {
return 'Invalid URL';
}
// Optionally restrict to allowed domains
$allowed_hosts = array('example.com', 'api.example.com');
$host = parse_url($url, PHP_URL_HOST);
if (!in_array($host, $allowed_hosts)) {
return 'URL not allowed';
}
$content = file_get_contents($url);
return $content;
}
add_shortcode('jsm_file_get_contents', 'jsm_file_get_contents_shortcode');
The patch adds URL validation using filter_var() and optionally restricts requests to a whitelist of allowed hosts.
Exploitation & Lab Setup
Red Team
Prerequisites:
- WordPress site with JSM
file_get_contents()Shortcode plugin version < 2.7.1. - Contributor-level account or higher.
Exploitation Steps:
- Log in to WordPress as a contributor.
- Create a new post or page.
- Insert the following shortcode to test SSRF:
[jsm_file_get_contents url="http://127.0.0.1:80/"] - Publish or preview the post. If the server returns the content of the local web server, SSRF is confirmed.
- For cloud metadata:
- AWS:
http://169.254.169.254/latest/meta-data/ - GCP:
http://metadata.google.internal/computeMetadata/v1/ - Azure:
http://169.254.169.254/metadata/instance?api-version=2021-02-01
- AWS:
- Use the SSRF to scan internal ports (e.g.,
http://192.168.1.1:8080/).
Lab Setup:
- Use a local WordPress installation (e.g., via Docker) with the vulnerable plugin.
- Set up a simple HTTP server on the same network to simulate internal services.
- Use a tool like
ngrokto expose the WordPress site for remote testing.
Blue Team
Detection:
- Monitor WordPress logs for unusual shortcode usage.
- Look for HTTP requests from the WordPress server to internal IP addresses (e.g., 10.x.x.x, 172.16.x.x, 192.168.x.x, 169.254.x.x).
- Use web application firewalls (WAF) to block requests to internal IPs from WordPress.
Mitigation:
- Immediately upgrade the plugin to version 2.7.1 or later.
- If upgrade is not possible, disable the plugin or remove contributor-level access.
- Implement network segmentation to limit the WordPress server's outbound access.
- Use a reverse proxy to filter outbound requests.
Indicators of Compromise (IOCs)
- Network IOCs:
- Outbound HTTP requests from the WordPress server to internal IP addresses (e.g., 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16).
- Requests to cloud metadata endpoints (e.g.,
169.254.169.254,metadata.google.internal). - Unusual User-Agent strings (default PHP
file_get_contentsmay not set a User-Agent).
- File IOCs:
- Presence of shortcodes with
urlparameter pointing to internal IPs in WordPress posts/pages.
- Presence of shortcodes with
- Log IOCs:
- WordPress debug logs showing
file_get_contents()calls with suspicious URLs. - Web server access logs showing requests to the WordPress site followed by outbound connections to internal IPs.
- WordPress debug logs showing
Detection Engineering
YARA Rule
rule CVE_2023_6991_SSRF_WordPress {
meta:
description = "Detects SSRF exploitation attempts via JSM file_get_contents shortcode"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2023-6991"
strings:
$shortcode = /\[jsm_file_get_contents\s+url\s*=\s*["'](http|https):\/\/(127\.0\.0\.1|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3})/ nocase
$metadata = "169.254.169.254"
$internal_ip = /(10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})/
condition:
$shortcode or ($metadata and $internal_ip)
}
Sigma Rule
title: CVE-2023-6991 SSRF via JSM file_get_contents Shortcode
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects SSRF attempts using the JSM file_get_contents shortcode in WordPress
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
service: access
detection:
selection:
cs-method: 'GET'
cs-uri-query|contains: 'jsm_file_get_contents'
cs-uri-query|re: 'url=(http|https):\/\/(127\.0\.0\.1|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3})'
condition: selection
falsepositives:
- Legitimate use of the shortcode with allowed external URLs (rare)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2023-6991 SSRF via JSM file_get_contents Shortcode"; flow:to_server,established; content:"jsm_file_get_contents"; http_uri; pcre:"/url=(http|https):\/\/(127\.0\.0\.1|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3})/i"; classtype:attempted-recon; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate Action: Upgrade the JSM
file_get_contents()Shortcode plugin to version 2.7.1 or later. - Workaround: If upgrade is not possible, disable the plugin entirely or remove contributor-level access from untrusted users.
- Network Controls: Implement outbound firewall rules to block the WordPress server from making requests to private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16).
- WAF Rules: Deploy web application firewall rules to block shortcodes containing internal IP addresses.
- Monitoring: Enable logging of all outbound HTTP requests from the WordPress server and alert on connections to internal IPs.
- Least Privilege: Review user roles and ensure only trusted users have contributor-level access or higher.
Valters IT
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.