@@ -386,14 +386,34 @@ public function xss_clean($str, $is_image = false)
386386 *
387387 * Note: Use rawurldecode() so it does not remove plus signs
388388 */
389- if (stripos ($ str , '% ' ) !== false ) {
390- do {
391- $ oldstr = $ str ;
392- $ str = rawurldecode ($ str );
393- $ str = preg_replace_callback ('#%(?:\s*[0-9a-f]){2,}#i ' , [$ this , '_urldecodespaces ' ], $ str );
394- } while ($ oldstr !== $ str );
395- unset($ oldstr );
396- }
389+
390+ // List of known malicious encoded patterns (hexadecimal)
391+ $ malicious_encodings = [
392+ '%3C ' => '< ' , // <
393+ '%3E ' => '> ' , // >
394+ '%22 ' => '" ' , // "
395+ '%27 ' => "' " , // '
396+ '%3D ' => '= ' , // =
397+ '%28 ' => '( ' , // (
398+ '%29 ' => ') ' , // )
399+ '%2F ' => '/ ' , // /
400+ '%5C ' => '\\' , // \
401+ '%3B ' => '; ' , // ;
402+ ];
403+
404+ // Normalize optionally spaced encodings like "% 3C"
405+ $ str = preg_replace_callback ('/%[\s]*[0-9a-fA-F]{2}/ ' , function ($ m ) use ($ malicious_encodings ) {
406+ // Normalize encoding: remove spaces
407+ $ clean = strtoupper (preg_replace ('/\s+/ ' , '' , $ m [0 ])); // e.g., "% 3C" → "%3C"
408+
409+ // If the encoding is a known malicious encoding, replace it
410+ if (isset ($ malicious_encodings [$ clean ])) {
411+ return $ malicious_encodings [$ clean ];
412+ }
413+
414+ // Return as-is if not malicious (e.g., malformed encodings like %2G, %3)
415+ return $ m [0 ];
416+ }, $ str );
397417
398418 /*
399419 * Convert character entities to ASCII
@@ -631,12 +651,6 @@ public function get_random_bytes($length)
631651 }
632652 }
633653
634- // Unfortunately, none of the following PRNGs is guaranteed to exist ...
635- if (defined ('MCRYPT_DEV_URANDOM ' ) && ($ output = mcrypt_create_iv ($ length , MCRYPT_DEV_URANDOM )) !== false ) {
636- return $ output ;
637- }
638-
639-
640654 if (is_readable ('/dev/urandom ' ) && ($ fp = fopen ('/dev/urandom ' , 'rb ' )) !== false ) {
641655 // Try not to waste entropy ...
642656 is_php ('5.4 ' ) && stream_set_chunk_size ($ fp , $ length );
@@ -779,24 +793,6 @@ public function strip_image_tags($str)
779793
780794 // ----------------------------------------------------------------
781795
782- /**
783- * URL-decode taking spaces into account
784- *
785- * @see https://github.com/bcit-ci/CodeIgniter/issues/4877
786- * @param array $matches
787- * @return string
788- */
789- protected function _urldecodespaces ($ matches )
790- {
791- $ input = $ matches [0 ];
792- $ nospaces = preg_replace ('#\s+# ' , '' , $ input );
793- return ($ nospaces === $ input )
794- ? $ input
795- : rawurldecode ($ nospaces );
796- }
797-
798- // ----------------------------------------------------------------
799-
800796 /**
801797 * Compact Exploded Words
802798 *
0 commit comments