WordPress / WordPress/theme-check

Blocklisted file-extension patterns are unanchored, so ordinary filenames fail the check

Open Beginner friendly
#504 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PHP
Stars
371
Forks
113
Avg merge
8m
Merged PRs (30d)
5

Description

Description

Check_File_Check matches its blocklist with preg_grep and no anchors, so a pattern intended to match a file extension matches that string anywhere in the path.

// checks/class-file-check.php
$blocklist = array(
    …
    '\.dat' => __( 'Customizer import file', 'theme-check' ),
    '\.xml' => __( 'XML file', 'theme-check' ),
    '\.sh'  => __( 'Shell script file', 'theme-check' ),
    …
);

foreach ( $blocklist as $file => $reason ) {
    if ( $filename = preg_grep( '/' . $file . '/', $filenames ) ) {

'\.sh' is the worst of these because sh begins many ordinary words. Any CSS or JS file whose name contains .sh… is reported as a shell script and raises a REQUIRED error, which fails the automated scan on upload.

Step-by-step reproduction instructions

  1. Add a stylesheet named assets/styles/tokens.sys.shape.css to any theme.
  2. Run Theme Check.

Expected: no error; it is a CSS file.

Actual:

REQUIRED: tokens.sys.shape.css Shell script file found. This file must not be in the production version of the theme.

Scope

Four patterns produce false positives on plausible filenames:

File Reported as
assets/styles/tokens.sys.shape.css Shell script file
assets/styles/tokens.sys.sheet.css Shell script file
assets/js/theme.shortcodes.js Shell script file
assets/styles/layout.shadow.css Shell script file
assets/data.database.json Customizer import file
assets/db.sqlite3 SQL dump file

.shape, .sheet, .shortcodes, .shadow, .database, and .sqlite3 are all normal names. shape in particular is the name of one of Material Design's token axes, so tokens.sys.shape.css is a natural filename for any theme following that system.

Suggested fix

Anchor the extension patterns at the end of the string:

if ( $filename = preg_grep( '/' . $file . '$/', $filenames ) ) {

That suits every entry that is an extension. Three entries are not extensions and would need care: '^.+[a-zA-Z0-9]' (hidden files, already anchored at the start), 'error_log', and '__MACOSX'. Splitting the blocklist into “extension” and “exact name” groups, each matched with its own anchoring, would be clearer than one array with mixed semantics.

Environment info

  • Theme Check 20260901
  • WordPress 7.1
  • PHP 8.3

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in checks/class-file-check.php at the blocklist and preg_grep call, then run Theme Check with the reproduction filename assets/styles/tokens.sys.shape.css. Keep extension matching limited to the end of the path while preserving the distinct hidden-file, error_log, and __MACOSX cases; done means the listed ordinary filenames pass without allowing blocked extensions through.

Written by the indexing model from the issue text.

Assessment

Tech stack
php
Domain
tooling
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.