Conversation
No .wav can be uploaded to a forum running this extension. The user is shown `MIME type mismatch detected: audio/vnd.wave vs audio/x-wav` and the file is deleted. Both names mean a RIFF/WAVE file: php-mime-detector returns the IANA registration, libmagic returns the name that predates it, and there is no .wav either library would answer differently for. The cross-validation in `getMimeType()` compares the two answers with `!==`, so any format the two libraries have picked different registered names for is rejected outright. Surveying every format php-mime-detector can identify, with real files and discarding samples fileinfo could not identify at all, 13 of 34 are unconditionally rejected on PHP 8.4 / libmagic 5.45: wav, flac, aiff, m4a, opus, avi, rar (both generations), rtf, xml, ttf, ico and deb. - Compare formats rather than strings, resolving alternative spellings through `EQUIVALENT_MIME_TYPES` first. `getMimeType()` still returns the detector's own spelling, so the MIME whitelist and the extension mapping see no change. - Nothing in the table crosses a format boundary, so the check keeps its purpose. Two groupings are wider than pure synonyms and are commented where they appear: Ogg, where libmagic names the container and php-mime-detector the codec inside it, and the SFNT font family, where some libmagic builds report `font/sfnt` for both TrueType and OpenType. - Canonicalisation also lower-cases and drops parameters, so `text/XML; charset=utf-8` no longer differs from `text/xml`. Every fixture in `FileUploadSecurityTest` behaves exactly as before, Polyglot .flif included — a FLIF header on an HTML body is still a mismatch, because `image/flif` and `text/html` are different formats. Tests: a real WAV round-trip (fails on 2.x today), a genuine mismatch that must still be rejected, and the equivalence table both ways — spellings that must merge, and formats that must stay apart. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #514.
The problem
getMimeType()cross-validates php-mime-detector against fileinfo and rejects the upload whenever the two answers are not the same string. Most formats have more than one registered name, and the two libraries did not always pick the same one, so a file that is exactly what it claims to be is deleted and the member is shownMIME type mismatch detected: audio/vnd.wave vs audio/x-wav..wavis the case that surfaced it —audio/vnd.waveis the IANA registration,audio/x-wavis the name that predates it, and no.wavexists for which the two libraries answer differently, so the format is unavailable on every install. Measuring the rest of the surface (real files wherever a header is not enough; samples fileinfo could not identify at all discarded), 13 of 34 identifiable formats are rejected unconditionally on PHP 8.4 / libmagic 5.45: wav, flac, aiff, m4a, opus, avi, rar v4 and v5, rtf, xml, ttf, ico, deb. Issue #514 has the full table.The fix
Compare the formats, not the strings.
EQUIVALENT_MIME_TYPESmaps alternative spellings onto one representative each;canonicalMimeType()applies it, after lower-casing and dropping any parameters, sotext/XML; charset=utf-8no longer differs fromtext/xml. A name that is not in the table is returned unchanged, so anything nobody has listed still has to match exactly.getMimeType()still returns$detectorMime— the detector's own spelling — so the admin's MIME whitelist and the extension mapping see exactly what they saw before.protected constread throughstatic::, so an install with an unusual libmagic build can extend it in a subclass.Two groupings are wider than pure synonyms, and are commented where they appear:
audio/ogg), php-mime-detector the codec inside it (audio/opus). Same bytes, and the container is what an admin whitelistingaudio/oggmeans.font/sfntfor either without distinguishing them. TTF against OTF is not a security boundary.Why this doesn't weaken the check
Nothing in the table crosses a format boundary, so a file whose magic bytes and whose libmagic signature describe genuinely different formats is still rejected.
I ran every fixture in
tests/fixturesthrough both the current class and the patched one, on Ubuntu 24.04 / libmagic 5.45:text/htmltext/htmltext/htmltext/htmltext/plaintext/plaintext/htmltext/htmlimage/svg+xmlimage/svg+xmlapplication/vnd.android.package-archiveIdentical in every row.
Polyglot.flifis the one the mismatch branch actually catches, and it still does:image/flifagainsttext/htmlis a real disagreement. The other malicious fixtures are caught downstream by the whitelist, as they are today.And the formats that change, same harness:
audio/vnd.waveaudio/x-flacaudio/aiffaudio/mp4audio/opusvideo/vnd.aviapplication/x-rar-compressedapplication/rtfapplication/xmlfont/ttfimage/x-iconapplication/x-deb13 formats go from rejected to accepted; none go the other way, and every returned value is the detector's own spelling, unchanged from what the whitelist matched against before.
Tests
Added to
tests/unit/Mime/MimeTypeDetectorTest.php:audio/vnd.waveis still what callers get — this one fails on 2.x today;Polyglot.fliffixture) that must still be rejected;null.composer test:unit167/167 green, PHPStan level 6 clean. The two libmagic-dependent tests skip themselves where fileinfo is missing or does not identify a WAV.No frontend change, so no
js/dist.