Make WordPress Core

Opened 6 weeks ago

Last modified 6 weeks ago

#64560 new defect (bug)

Function get_stylesheet_directory_uri() can expose server path when using a theme directory outside the document root

Reported by: emrl's profile emrl Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: General Keywords:
Focuses: Cc:

Description

For several years we have been using register_theme_directory() to register a theme directory outside of the document root. I understand that it is unconventional, but it has worked perfectly with no issues until now. It was done to follow best practices to keep PHP code (functions.php, classes, templates) above any public directories.

The Speculative Loading feature now excludes some base/default directories, and does not allow a real way to modify them via filter/action.

WP_URL_Pattern_Prefixer::get_default_contexts() has no filter.

wp_speculation_rules_href_exclude_paths filter specifically runs before those default contexts are added, so they cannot be removed.

wp_load_speculation_rules action does not allow modification of any rules as WP_Speculation_Rules has no method for removing/modifying rules, it can only fully replace them. So to remove the template or stylesheet context, one would need to duplicate the entire main rule conditions from wp_get_speculation_rules(), which is fragile at best.

Themes outside the document root is rare, but there doesn't seem to be anything preventing that, and everything else in WordPress seems to run just fine doing so.

A quick fix has been for us to use the filters stylesheet_directory_uri and template_directory_uri to remove the absolute server paths, but this still leaves a potentially valid and real WordPress page URL on the excluded list.

Example of output below, the server path is exposed in the HTML: /home/USER/apps/APP_NAME/releases/485/theme-name/*

<script type="speculationrules">
{
  "prefetch": [
    {
      "source": "document",
      "where": {
        "and": [
          {
            "href_matches": "/*"
          },
          {
            "not": {
              "href_matches": [
                "/wp-*.php",
                "/wp-admin/*",
                "/wp-content/uploads/*",
                "/wp-content/*",
                "/wp-content/plugins/*",
                "/home/USER/apps/APP_NAME/releases/485/theme-name/*",
                "/*\\?(.+)"
              ]
            }
          },
          {
            "not": {
              "selector_matches": "a[rel~=\"nofollow\"]"
            }
          },
          {
            "not": {
              "selector_matches": ".no-prefetch, .no-prefetch a"
            }
          }
        ]
      },
      "eagerness": "conservative"
    }
  ]
}
</script>

Change History (6)

#1 @westonruter
6 weeks ago

  • Focuses performance added
  • Version set to 6.8

Is the issue with Speculative Loading, or is the issue that get_stylesheet_directory_uri() is returning an invalid URL given your unusual theme location?

(Introduced in r59837 for #62503.)

#2 @emrl
6 weeks ago

@westonruter Right, I'm not sure really. The Speculative API is where I happened to notice it, but it was just unexpected behavior for get_stylesheet_directory_uri() to ever return an absolute server path.

I know the issue goes away when a typical theme location is used, but I figured I would open the bug to raise awareness that it could happen.

#3 @westonruter
6 weeks ago

So if you just call get_stylesheet_directory_uri() somewhere on the page to, for example, construct the URL for a static image asset in the theme, does this also break for you?

#4 @emrl
6 weeks ago

Yes, same result. I would not expect that function to be useful in our case of course, but as far as I know nothing else has automatically output the result of it to the frontend until now.

#5 @westonruter
6 weeks ago

  • Focuses performance removed
  • Summary changed from Speculative Loading API can expose server path when using a theme directory outside the document root to Function get_stylesheet_directory_uri() can expose server path when using a theme directory outside the document root
  • Version 6.8 deleted

OK, since this isn't specific to Speculative Loading, I'm making this more general to be about get_stylesheet_directory_uri().

Providing more details (e.g. sample code) about how specifically you are registering your theme root would be helpful for others looking to reproduce the issue.

#6 @emrl
6 weeks ago

Thank you. We have a must-use plugin that calls register_theme_directory like this basically.

<?php

if (!defined('WP_DEFAULT_THEME')) {
    // Document root is `/home/user/app/public`
    register_theme_directory('/home/user/app');
}
Note: See TracTickets for help on using tickets.