+ /**
+ * Check a block of CSS or CSS fragment for anything that looks like
+ * it is bringing in remote code.
+ * @param string $value a string of CSS
+ * @param bool $propOnly only check css properties (start regex with :)
+ * @return bool true if the CSS contains an illegal string, false if otherwise
+ */
+ private static function checkCssFragment( $value ) {
+
+ # Forbid external stylesheets, for both reliability and to protect viewer's privacy
+ if ( strpos( $value, '@import' ) !== false ) {
+ return true;
+ }
+
+ # We allow @font-face to embed fonts with data: urls, so we snip the string
+ # 'url' out so this case won't match when we check for urls below
+ $pattern = '!(@font-face\s*{[^}]*src:)url(\("data:;base64,)!im';
+ $value = preg_replace( $pattern, '$1$2', $value );
+
+ # Check for remote and executable CSS. Unlike in Sanitizer::checkCss, the CSS
+ # properties filter and accelerator don't seem to be useful for xss in SVG files.
+ # Expression and -o-link don't seem to work either, but filtering them here in case.
+ # Additionally, we catch remote urls like url("http:..., url('http:..., url(http:...,
+ # but not local ones such as url("#..., url('#..., url(#....
+ if ( preg_match( '!expression
+ | -o-link\s*:
+ | -o-link-source\s*:
+ | -o-replace\s*:!imx', $value ) ) {
+ return true;
+ }
+
+ if ( preg_match_all(
+ "!(\s*(url|image|image-set)\s*\(\s*[\"']?\s*[^#]+.*?\))!sim",
+ $value,
+ $matches
+ ) !== 0
+ ) {
+ # TODO: redo this in one regex. Until then, url("#whatever") matches the first
+ foreach ( $matches[1] as $match ) {
+ if ( !preg_match( "!\s*(url|image|image-set)\s*\(\s*(#|'#|\"#)!im", $match ) ) {
+ return true;
+ }
+ }
+ }
+
+ if ( preg_match( '/[\000-\010\013\016-\037\177]/', $value ) ) {
+ return true;
+ }
+
+ return false;
+ }
+