@@ -2349,17 +2349,52 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
23492349 $ real_mime = finfo_file ( $ finfo , $ file );
23502350 finfo_close ( $ finfo );
23512351
2352+ // fileinfo often misidentifies obscure files as one of these types
2353+ $ nonspecific_types = array (
2354+ 'application/octet-stream ' ,
2355+ 'application/encrypted ' ,
2356+ 'application/CDFV2-encrypted ' ,
2357+ 'application/zip ' ,
2358+ );
2359+
23522360 /*
2353- * If $real_mime doesn't match what we're expecting, we need to do some extra
2354- * vetting of application mime types to make sure this type of file is allowed.
2355- * Other mime types are assumed to be safe, but should be considered unverified .
2361+ * If $real_mime doesn't match the content type we're expecting from the file's extension,
2362+ * we need to do some additional vetting. Media types and those listed in $nonspecific_types are
2363+ * allowed some leeway, but anything else must exactly match the real content type .
23562364 */
2357- if ( $ real_mime && ( $ real_mime !== $ type ) && ( 0 === strpos ( $ real_mime , 'application ' ) ) ) {
2358- $ allowed = get_allowed_mime_types ();
2365+ if ( in_array ( $ real_mime , $ nonspecific_types , true ) ) {
2366+ // File is a non-specific binary type. That's ok if it's a type that generally tends to be binary.
2367+ if ( !in_array ( substr ( $ type , 0 , strcspn ( $ type , '/ ' ) ), array ( 'application ' , 'video ' , 'audio ' ) ) ) {
2368+ $ type = $ ext = false ;
2369+ }
2370+ } elseif ( 0 === strpos ( $ real_mime , 'video/ ' ) || 0 === strpos ( $ real_mime , 'audio/ ' ) ) {
2371+ /*
2372+ * For these types, only the major type must match the real value.
2373+ * This means that common mismatches are forgiven: application/vnd.apple.numbers is often misidentified as application/zip,
2374+ * and some media files are commonly named with the wrong extension (.mov instead of .mp4)
2375+ */
23592376
2360- if ( ! in_array ( $ real_mime , $ allowed ) ) {
2377+ if ( substr ( $ real_mime , 0 , strcspn ( $ real_mime , '/ ' ) ) !== substr ( $ type , 0 , strcspn ( $ type , '/ ' ) ) ) {
2378+ $ type = $ ext = false ;
2379+ }
2380+ } else {
2381+ if ( $ type !== $ real_mime ) {
2382+ /*
2383+ * Everything else including image/* and application/*:
2384+ * If the real content type doesn't match the file extension, assume it's dangerous.
2385+ */
23612386 $ type = $ ext = false ;
23622387 }
2388+
2389+ }
2390+ }
2391+
2392+ // The mime type must be allowed
2393+ if ( $ type ) {
2394+ $ allowed = get_allowed_mime_types ();
2395+
2396+ if ( ! in_array ( $ type , $ allowed ) ) {
2397+ $ type = $ ext = false ;
23632398 }
23642399 }
23652400
0 commit comments