@@ -2341,17 +2341,52 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
23412341 $ real_mime = finfo_file ( $ finfo , $ file );
23422342 finfo_close ( $ finfo );
23432343
2344+ // fileinfo often misidentifies obscure files as one of these types
2345+ $ nonspecific_types = array (
2346+ 'application/octet-stream ' ,
2347+ 'application/encrypted ' ,
2348+ 'application/CDFV2-encrypted ' ,
2349+ 'application/zip ' ,
2350+ );
2351+
23442352 /*
2345- * If $real_mime doesn't match what we're expecting, we need to do some extra
2346- * vetting of application mime types to make sure this type of file is allowed.
2347- * Other mime types are assumed to be safe, but should be considered unverified .
2353+ * If $real_mime doesn't match the content type we're expecting from the file's extension,
2354+ * we need to do some additional vetting. Media types and those listed in $nonspecific_types are
2355+ * allowed some leeway, but anything else must exactly match the real content type .
23482356 */
2349- if ( $ real_mime && ( $ real_mime !== $ type ) && ( 0 === strpos ( $ real_mime , 'application ' ) ) ) {
2350- $ allowed = get_allowed_mime_types ();
2357+ if ( in_array ( $ real_mime , $ nonspecific_types , true ) ) {
2358+ // File is a non-specific binary type. That's ok if it's a type that generally tends to be binary.
2359+ if ( !in_array ( substr ( $ type , 0 , strcspn ( $ type , '/ ' ) ), array ( 'application ' , 'video ' , 'audio ' ) ) ) {
2360+ $ type = $ ext = false ;
2361+ }
2362+ } elseif ( 0 === strpos ( $ real_mime , 'video/ ' ) || 0 === strpos ( $ real_mime , 'audio/ ' ) ) {
2363+ /*
2364+ * For these types, only the major type must match the real value.
2365+ * This means that common mismatches are forgiven: application/vnd.apple.numbers is often misidentified as application/zip,
2366+ * and some media files are commonly named with the wrong extension (.mov instead of .mp4)
2367+ */
23512368
2352- if ( ! in_array ( $ real_mime , $ allowed ) ) {
2369+ if ( substr ( $ real_mime , 0 , strcspn ( $ real_mime , '/ ' ) ) !== substr ( $ type , 0 , strcspn ( $ type , '/ ' ) ) ) {
2370+ $ type = $ ext = false ;
2371+ }
2372+ } else {
2373+ if ( $ type !== $ real_mime ) {
2374+ /*
2375+ * Everything else including image/* and application/*:
2376+ * If the real content type doesn't match the file extension, assume it's dangerous.
2377+ */
23532378 $ type = $ ext = false ;
23542379 }
2380+
2381+ }
2382+ }
2383+
2384+ // The mime type must be allowed
2385+ if ( $ type ) {
2386+ $ allowed = get_allowed_mime_types ();
2387+
2388+ if ( ! in_array ( $ type , $ allowed ) ) {
2389+ $ type = $ ext = false ;
23552390 }
23562391 }
23572392
0 commit comments