WordPress / WordPress/theme-check
Blocklisted file-extension patterns are unanchored, so ordinary filenames fail the check
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
- Add a stylesheet named
assets/styles/tokens.sys.shape.cssto any theme. - Run Theme Check.
Expected: no error; it is a CSS file.
Actual:
REQUIRED:
tokens.sys.shape.cssShell 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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