Make WordPress Core

Opened 12 years ago

Last modified 8 hours ago

#30495 new defect (bug)

Unicode character U+000B is not removed by sanitize_file_name

Reported by: Craxic Owned by:
Priority: normal Milestone: Awaiting Review
Component: Formatting Version: 4.0.1
Severity: normal Keywords: has-patch has-unit-tests
Cc: Focuses:

Description

It seems that the following expression is true:

json_encode(sanitize_file_name(json_decode('"\u000B"'))) == "\u000b"

On Google App Engine, for example, a file name with a U+000B character cannot be saved.

Since the description of the function states:

Removes special characters that are illegal in filenames on certain
operating systems and special characters requiring special escaping
to manipulate at the command line.

... then I think this is a bug.

Thanks!

Attachments (1)

line-tabulation-sanitization.30495.diff​ (1.7 KB ) - added by sanchothefat 11 years ago.
Adds a step to remove all control characters in the 1-31 then mops up white space. Has unit test.

Download all attachments as: .zip

Change History (8)

This ticket was mentioned in ​Slack in #core by jorbin. ​View the logs.


11 years ago

#2 @jorbin
11 years ago

  • Component Filesystem API → Formatting
  • Keywords needs-patch needs-unit-tests added

There might be a benefit in a check inside sanitize_file_name to remove everything that matches [:space:]. This is going to need both unit tests and a patch to move forward.

@sanchothefat
11 years ago

Adds a step to remove all control characters in the 1-31 then mops up white space. Has unit test.

#3 @sanchothefat
11 years ago

  • Keywords has-patch has-unit-tests added; needs-patch needs-unit-tests removed

#4 @mgutt
10 years ago

Regarding "then mops up white space" take a look at this changeset:
https://core.trac.wordpress.org/changeset/29715

Last edited 10 years ago by mgutt (previous) (diff)

This ticket was mentioned in ​Slack in #core-privacy by desrosj. ​View the logs.


8 years ago

#6 @kyunghan
10 days ago

Reproduction test report

I reproduced this on WordPress 7.2-alpha-64042 using PHP 8.4.26 on Windows x64. The isolated installation uses SQLite 3.53.4 with SQLite Database Integration 1.8.0, Twenty Twenty-Five, and no active regular plugins. The tested function is independent of database queries.

Steps

Run the following in a bootstrapped WordPress environment:

$input = "menu\x0B2026.pdf";
$output = sanitize_file_name( $input );
echo bin2hex( $output );

Expected: the U+000B control character is removed or replaced so that it is absent from the sanitized filename.

Actual: 6d656e750b323032362e706466. U+000B remains in menu\x0B2026.pdf.

Additional coverage

I ran the same filename test for all 32 ASCII control values U+0000 through U+001F. U+0000, U+0009, U+000A and U+000D are removed/replaced; the remaining 28 controls are retained, including U+000B and U+000C.

I then attempted to write the actual sanitized filenames to an isolated local directory using Python 3.12 on Windows. All 28 filenames containing a retained control failed with OSError: [Errno 22] Invalid argument. The four filenames whose controls were removed/replaced were saved successfully. This confirms a current Windows filesystem impact, in addition to the Google App Engine case in the original report.

Controls with ordinary spaces, accented Latin characters and Korean characters were also tested. menu 2026.pdf becomes menu-2026.pdf, and café-menu.pdf becomes cafe-menu.pdf. Korean characters remain intact while the ordinary space becomes a dash.

Result: the issue still reproduces on current nightly. The C0 control range needs additional coverage; replacing Unicode space-separator characters alone does not address these controls. I did not test the historical attached patch.

AI assistance: OpenAI Codex prepared and executed the scripts and helped draft this report. The results above come from the stated local WordPress installation and actual Windows file-write attempts.

This ticket was mentioned in ​PR #14198 on ​WordPress/wordpress-develop by ​@salvatorecorsi.


8 hours ago
#7

sanitize_file_name( "menu\x0B2026.pdf" ) retains the vertical tab, so the result can still be an invalid filename on Windows. The ticket's recent reproduction also identifies 27 other C0 control characters that the default sanitizer retains.

Add these 28 characters to the default removal list before sanitize_file_name_chars, preserving filter customization. Existing NUL removal and TAB/LF/CR replacement with a dash remain intact. Tests cover all 32 C0 values, leading/trailing/mixed controls, accents and Unicode, multiple extensions, the removal-list override and the final filename filter.

This builds on the C0-control approach proposed in sanchothefat's historical patch on the ticket, while preserving the current whitespace and public-filter behavior.

Reproduction

Run sanitize_file_name( "menu\x0B2026.pdf" ). Before this change its hex output contains 0b: 6d656e750b323032362e706466. The expected result is menu2026.pdf, with that control removed. "menu\t2026.pdf" should continue to become menu-2026.pdf.

Validation

Native PHP 8.3.28, PHPUnit 9.6.38 and private MariaDB:

  • Before changing the implementation, the 42 new cases produced 38 failures, including all 28 previously retained C0 values. The existing NUL and TAB/LF/CR cases passed.
  • The complete filename test class passed 62 tests and 76 assertions.
  • All Tests_Formatting_* classes completed 1,735 tests and 2,558 assertions, with no failures and five PHPUnit 9 deprecation warnings from unchanged wpStripAllTags and wpTrimExcerpt tests.
  • PHPCS, PHP compatibility, PHP syntax checks for both files and git diff --check passed.

Commands executed through the local serialized PHPUnit runner correspond to:

php vendor/bin/phpunit -c phpunit.xml.dist tests/phpunit/tests/formatting/sanitizeFileName.php
php vendor/bin/phpunit -c phpunit.xml.dist --filter '^Tests_Formatting_'
php vendor/bin/phpcs --standard=phpcs.xml.dist --parallel=1 src/wp-includes/formatting.php tests/phpunit/tests/formatting/sanitizeFileName.php
php vendor/bin/phpcs --standard=phpcompat.xml.dist --parallel=1 src/wp-includes/formatting.php tests/phpunit/tests/formatting/sanitizeFileName.php

The complete Core suite, other PHP versions, multisite, asset builds and E2E were not run locally.

Use of AI Tools

AI assistance: Yes
Tool(s): OpenAI Codex
Model(s): GPT-6
Used for: Ticket investigation, implementation, regression tests, local validation, this description and independent automated review. No human review is claimed; this PR is submitted for contributor and maintainer review.

Note: See TracTickets for help on using tickets.