From 8e4f547d31e347b51d5b490656eadd998d81d2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Tue, 4 Feb 2025 12:46:53 +0100 Subject: [PATCH 1/8] add(gh-552): support for @media rule --- .../org/owasp/validator/css/CssHandler.java | 75 ++- .../org/owasp/validator/css/CssParser.java | 111 +++++ .../org/owasp/validator/css/CssValidator.java | 41 ++ .../validator/css/media/CssMediaFeature.java | 28 ++ .../validator/css/media/CssMediaQuery.java | 36 ++ .../css/media/CssMediaQueryList.java | 44 ++ .../media/CssMediaQueryLogicalOperator.java | 18 + .../validator/css/media/CssMediaType.java | 18 + src/main/resources/antisamy.xml | 457 ++++++++++++++++++ .../validator/html/test/AntiSamyTest.java | 38 ++ 10 files changed, 846 insertions(+), 20 deletions(-) create mode 100644 src/main/java/org/owasp/validator/css/media/CssMediaFeature.java create mode 100644 src/main/java/org/owasp/validator/css/media/CssMediaQuery.java create mode 100644 src/main/java/org/owasp/validator/css/media/CssMediaQueryList.java create mode 100644 src/main/java/org/owasp/validator/css/media/CssMediaQueryLogicalOperator.java create mode 100644 src/main/java/org/owasp/validator/css/media/CssMediaType.java diff --git a/src/main/java/org/owasp/validator/css/CssHandler.java b/src/main/java/org/owasp/validator/css/CssHandler.java index 7be3875..038ec19 100644 --- a/src/main/java/org/owasp/validator/css/CssHandler.java +++ b/src/main/java/org/owasp/validator/css/CssHandler.java @@ -35,6 +35,9 @@ import java.util.LinkedList; import java.util.List; import java.util.ResourceBundle; +import org.owasp.validator.css.media.CssMediaFeature; +import org.owasp.validator.css.media.CssMediaQuery; +import org.owasp.validator.css.media.CssMediaQueryList; import org.owasp.validator.html.InternalPolicy; import org.owasp.validator.html.Policy; import org.owasp.validator.html.ScanException; @@ -96,6 +99,10 @@ public class CssHandler implements DocumentHandler { */ private boolean selectorOpen = false; + private MediaState mediaState = MediaState.OUTSIDE; + + private enum MediaState {INSIDE, OUTSIDE, DENIED} + /** * Constructs a handler for stylesheets using the given policy. The List of embedded stylesheets * produced by this constructor is now available via the getImportedStylesheetsURIList() method. @@ -340,26 +347,6 @@ public void endFontFace() throws CSSException { // CSS2 Font Face declaration - ignore this for now } - /* - * (non-Javadoc) - * - * @see org.w3c.css.sac.DocumentHandler#startMedia(org.w3c.css.sac.SACMediaList) - */ - @Override - public void startMedia(SACMediaList media) throws CSSException { - // CSS2 Media declaration - ignore this for now - } - - /* - * (non-Javadoc) - * - * @see org.w3c.css.sac.DocumentHandler#endMedia(org.w3c.css.sac.SACMediaList) - */ - @Override - public void endMedia(SACMediaList media) throws CSSException { - // CSS2 Media declaration - ignore this for now - } - /* * (non-Javadoc) * @@ -538,4 +525,52 @@ public void property(String name, LexicalUnit value, boolean important) throws C })); } } + + @Override + public void startMedia(SACMediaList media) throws CSSException { + CssMediaQueryList mediaQueryList = (CssMediaQueryList) media; + + boolean first = true; + for (CssMediaQuery query : mediaQueryList.getMediaQueries()) { + if (!validator.isValidMediaQuery(query)) { + continue; + } + if (first) { + styleSheet.append("@media "); + first = false; + } else { + styleSheet.append(", "); + } + if (query.getLogicalOperator() != null) { + styleSheet.append(query.getLogicalOperator()).append(' '); + } + styleSheet.append(query.getMediaType()); + for (CssMediaFeature feature : query.getMediaFeatures()) { + styleSheet.append(" and ("); + styleSheet.append(feature.getName()); + if (feature.getExpression() != null) { + styleSheet.append(": "); + styleSheet.append(validator.lexicalValueToString(feature.getExpression())); + } + styleSheet.append(')'); + } + } + + if (!first) { + styleSheet.append(" {"); + styleSheet.append('\n'); + mediaState = MediaState.INSIDE; + } else { + mediaState = MediaState.DENIED; + } + } + + @Override + public void endMedia(SACMediaList media) throws CSSException { + if (mediaState == MediaState.INSIDE) { + styleSheet.append('}'); + styleSheet.append('\n'); + } + mediaState = MediaState.OUTSIDE; + } } diff --git a/src/main/java/org/owasp/validator/css/CssParser.java b/src/main/java/org/owasp/validator/css/CssParser.java index 832f6c9..65f98cd 100644 --- a/src/main/java/org/owasp/validator/css/CssParser.java +++ b/src/main/java/org/owasp/validator/css/CssParser.java @@ -28,7 +28,15 @@ */ package org.owasp.validator.css; +import static org.owasp.validator.css.media.CssMediaQueryLogicalOperator.AND; + +import org.apache.batik.css.parser.CSSSACMediaList; import org.apache.batik.css.parser.LexicalUnits; +import org.owasp.validator.css.media.CssMediaFeature; +import org.owasp.validator.css.media.CssMediaQuery; +import org.owasp.validator.css.media.CssMediaQueryList; +import org.owasp.validator.css.media.CssMediaQueryLogicalOperator; +import org.owasp.validator.css.media.CssMediaType; import org.w3c.css.sac.CSSException; import org.w3c.css.sac.CSSParseException; import org.w3c.css.sac.LexicalUnit; @@ -96,4 +104,107 @@ protected void parseStyleDeclaration(final boolean inSheet) throws CSSException } } } + + @Override + protected CSSSACMediaList parseMediaList() { + CssMediaQueryList mediaList = new CssMediaQueryList(); + + mediaList.append(parseMediaQuery()); + while (current == LexicalUnits.COMMA) { + nextIgnoreSpaces(); + mediaList.append(parseMediaQuery()); + } + + return mediaList; + } + + protected CssMediaQuery parseMediaQuery() { + CssMediaQuery query = new CssMediaQuery(); + switch (current) { + case LexicalUnits.LEFT_BRACE: + query.setMediaType(CssMediaType.ALL); + query.addMediaFeature(parseMediaFeature()); + break; + case LexicalUnits.IDENTIFIER: + final CssMediaQueryLogicalOperator logicalOperator = CssMediaQueryLogicalOperator.parse(scanner.getStringValue()); + if (logicalOperator != null) { + query.setLogicalOperator(logicalOperator); + if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) { + throw createCSSParseException("identifier"); + } + } + final CssMediaType mediaType = CssMediaType.parse(scanner.getStringValue()); + if (mediaType == null) { + throw createCSSParseException("identifier"); + } + query.setMediaType(mediaType); + nextIgnoreSpaces(); + break; + default: + throw createCSSParseException("identifier"); + } + + while (current == LexicalUnits.IDENTIFIER && CssMediaQueryLogicalOperator.parse(scanner.getStringValue()) == AND) { + nextIgnoreSpaces(); + query.addMediaFeature(parseMediaFeature()); + } + return query; + } + + protected CssMediaFeature parseMediaFeature() { + if (current != LexicalUnits.LEFT_BRACE) { + throw createCSSParseException("'(' expected."); + } + nextIgnoreSpaces(); + String namePrefix = ""; + if (current == LexicalUnits.MINUS) { + nextIgnoreSpaces(); + namePrefix = "-"; + } + if (current != LexicalUnits.IDENTIFIER) { + throw createCSSParseException("identifier"); + } + String name = namePrefix + scanner.getStringValue(); + nextIgnoreSpaces(); + LexicalUnit exp = null; + if (current == LexicalUnits.COLON) { + nextIgnoreSpaces(); + exp = parseTerm(null); + } + if (current != LexicalUnits.RIGHT_BRACE) { + throw createCSSParseException("right.brace"); + } + nextIgnoreSpaces(); + + return new CssMediaFeature(name, exp); + } + + @Override + protected void parseMediaRule() { + CSSSACMediaList ml = parseMediaList(); + try { + documentHandler.startMedia(ml); + + if (current != LexicalUnits.LEFT_CURLY_BRACE) { + reportError("left.curly.brace"); + } else { + nextIgnoreSpaces(); + + loop: + for (; ; ) { + switch (current) { + case LexicalUnits.EOF: + case LexicalUnits.RIGHT_CURLY_BRACE: + break loop; + default: + parseRuleSet(); + } + } + + nextIgnoreSpaces(); + } + } finally { + documentHandler.endMedia(ml); + } + } } diff --git a/src/main/java/org/owasp/validator/css/CssValidator.java b/src/main/java/org/owasp/validator/css/CssValidator.java index d9547ba..e23cc4a 100644 --- a/src/main/java/org/owasp/validator/css/CssValidator.java +++ b/src/main/java/org/owasp/validator/css/CssValidator.java @@ -31,9 +31,13 @@ import java.text.DecimalFormat; import java.util.Iterator; import java.util.regex.Pattern; +import org.apache.batik.css.parser.CSSLexicalUnit; +import org.owasp.validator.css.media.CssMediaFeature; +import org.owasp.validator.css.media.CssMediaQuery; import org.owasp.validator.html.Policy; import org.owasp.validator.html.ScanException; import org.owasp.validator.html.model.AntiSamyPattern; +import org.owasp.validator.html.model.Attribute; import org.owasp.validator.html.model.Property; import org.owasp.validator.html.util.HTMLEntityEncoder; import org.w3c.css.sac.AttributeCondition; @@ -56,6 +60,8 @@ */ public class CssValidator { + private static final LexicalUnit EMPTYSTRINGLEXICALUNIT = CSSLexicalUnit.createString(LexicalUnit.SAC_STRING_VALUE, "", null); + private final Policy policy; /** @@ -406,6 +412,41 @@ public String lexicalValueToString(LexicalUnit lu) { } } + /** + * Returns whether the given {@link CssMediaQuery} is valid + * + * @param mediaQuery mediaQuery + * @return valid mediaQuery? + */ + public boolean isValidMediaQuery(CssMediaQuery mediaQuery) { + // check mediaType against allowed media-HTML-Attribute + Attribute mediaAttribute = policy.getTagByLowercaseName("style").getAttributeByName("media"); + if (mediaAttribute == null) { + return false; + } + + String mediaTypeString = mediaQuery.getMediaType().toString().toLowerCase(); + boolean isValidMediaType = mediaAttribute.containsAllowedValue(mediaTypeString) || mediaAttribute.matchesAllowedExpression(mediaTypeString); + if (!isValidMediaType) { + return false; + } + + for (CssMediaFeature feature : mediaQuery.getMediaFeatures()) { + LexicalUnit expression = feature.getExpression(); + if (expression == null) { + expression = EMPTYSTRINGLEXICALUNIT; + } + if (!isValidMediaFeature(feature.getName(), expression)) { + return false; + } + } + return true; + } + + private boolean isValidMediaFeature(String name, LexicalUnit lu) { + return isValidProperty("_mediafeature_" + name, lu); + } + /** * Returns color value as int. * Maps percentages to values between 0 and 255. diff --git a/src/main/java/org/owasp/validator/css/media/CssMediaFeature.java b/src/main/java/org/owasp/validator/css/media/CssMediaFeature.java new file mode 100644 index 0000000..f4a34c5 --- /dev/null +++ b/src/main/java/org/owasp/validator/css/media/CssMediaFeature.java @@ -0,0 +1,28 @@ +package org.owasp.validator.css.media; + +import org.w3c.css.sac.LexicalUnit; + +public class CssMediaFeature { + + private final String name; + private final LexicalUnit expression; + + /** + * Constructor. + * + * @param name Feature-name + * @param expression expression, may be null + */ + public CssMediaFeature(String name, LexicalUnit expression) { + this.name = name; + this.expression = expression; + } + + public String getName() { + return name; + } + + public LexicalUnit getExpression() { + return expression; + } +} diff --git a/src/main/java/org/owasp/validator/css/media/CssMediaQuery.java b/src/main/java/org/owasp/validator/css/media/CssMediaQuery.java new file mode 100644 index 0000000..6005200 --- /dev/null +++ b/src/main/java/org/owasp/validator/css/media/CssMediaQuery.java @@ -0,0 +1,36 @@ +package org.owasp.validator.css.media; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class CssMediaQuery { + + private CssMediaQueryLogicalOperator logicalOperator; + private CssMediaType mediaType; + private final List mediaFeatures = new ArrayList<>(); + + public CssMediaQueryLogicalOperator getLogicalOperator() { + return logicalOperator; + } + + public void setLogicalOperator(CssMediaQueryLogicalOperator logicalOperator) { + this.logicalOperator = logicalOperator; + } + + public CssMediaType getMediaType() { + return mediaType; + } + + public void setMediaType(CssMediaType mediaType) { + this.mediaType = mediaType; + } + + public void addMediaFeature(CssMediaFeature mediaFeature) { + mediaFeatures.add(mediaFeature); + } + + public List getMediaFeatures() { + return Collections.unmodifiableList(mediaFeatures); + } +} diff --git a/src/main/java/org/owasp/validator/css/media/CssMediaQueryList.java b/src/main/java/org/owasp/validator/css/media/CssMediaQueryList.java new file mode 100644 index 0000000..52fe815 --- /dev/null +++ b/src/main/java/org/owasp/validator/css/media/CssMediaQueryList.java @@ -0,0 +1,44 @@ +package org.owasp.validator.css.media; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.batik.css.parser.CSSSACMediaList; + +public class CssMediaQueryList extends CSSSACMediaList { + + private final List mediaQueries = new ArrayList<>(); + + @Override + public int getLength() { + return mediaQueries.size(); + } + + /** + * Use {@link CssMediaQueryList#getMediaQueryAt(int)} instead. + * {@inheritDoc} + */ + @Override + public String item(int index) { + CssMediaQuery query = getMediaQueryAt(index); + if (query.getMediaFeatures().isEmpty() && query.getLogicalOperator() == null) { + return query.getMediaType().toString(); + } else { + throw new UnsupportedOperationException("CSS3 MediaQuery unsupported"); + } + } + + public CssMediaQuery getMediaQueryAt(int index) { + return mediaQueries.get(index); + } + + public List getMediaQueries() { + return Collections.unmodifiableList(mediaQueries); + } + + + public void append(CssMediaQuery mediaQuery) { + mediaQueries.add(mediaQuery); + } +} diff --git a/src/main/java/org/owasp/validator/css/media/CssMediaQueryLogicalOperator.java b/src/main/java/org/owasp/validator/css/media/CssMediaQueryLogicalOperator.java new file mode 100644 index 0000000..adbad04 --- /dev/null +++ b/src/main/java/org/owasp/validator/css/media/CssMediaQueryLogicalOperator.java @@ -0,0 +1,18 @@ +package org.owasp.validator.css.media; + +public enum CssMediaQueryLogicalOperator { + AND, NOT, ONLY, OR; + + @Override + public String toString() { + return super.toString().toLowerCase(); + } + + public static CssMediaQueryLogicalOperator parse(String operator) { + try { + return CssMediaQueryLogicalOperator.valueOf(operator.toUpperCase()); + } catch (IllegalArgumentException e) { + return null; + } + } +} diff --git a/src/main/java/org/owasp/validator/css/media/CssMediaType.java b/src/main/java/org/owasp/validator/css/media/CssMediaType.java new file mode 100644 index 0000000..3dd9ab7 --- /dev/null +++ b/src/main/java/org/owasp/validator/css/media/CssMediaType.java @@ -0,0 +1,18 @@ +package org.owasp.validator.css.media; + +public enum CssMediaType { + ALL, PRINT, SCREEN; + + @Override + public String toString() { + return super.toString().toLowerCase(); + } + + public static CssMediaType parse(String mediaType) { + try { + return CssMediaType.valueOf(mediaType.toUpperCase()); + } catch (IllegalArgumentException e) { + return null; + } + } +} diff --git a/src/main/resources/antisamy.xml b/src/main/resources/antisamy.xml index 43c1b86..91c1313 100644 --- a/src/main/resources/antisamy.xml +++ b/src/main/resources/antisamy.xml @@ -101,10 +101,13 @@ + + + @@ -2716,6 +2719,460 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java b/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java index 4699c24..706484c 100644 --- a/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java +++ b/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java @@ -34,6 +34,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -67,6 +68,7 @@ import org.owasp.validator.html.model.Property; import org.owasp.validator.html.model.Tag; import org.owasp.validator.html.scan.Constants; +import org.w3c.css.sac.CSSParseException; /** * This class tests AntiSamy functionality and the basic policy file which should be immune to XSS @@ -2755,4 +2757,40 @@ public void testGithubIssue546FaultyPercentagesGetFilteredByRegex() throws ScanE assertEquals(expectedCleanHtml, crDom.getCleanHTML()); assertEquals(expectedCleanHtml, crSax.getCleanHTML()); } + + @Test + public void testGithubIssue552() throws ScanException, PolicyException { + checkStyleTag("@media screen {}", + "@media screen {\n}\n"); + + checkStyleTag("@media screen,print {}", + "@media screen, print {\n}\n"); + + checkStyleTag("@media only screen and (max-width: 639px) and (min-width: 300px) {}", + "@media only screen and (max-width: 639.0px) and (min-width: 300.0px) {\n}\n"); + + checkStyleTag("@media not screen, screen and (color), print and (orientation: portrait) {}", + "@media not screen, screen and (color), print and (orientation: portrait) {\n}\n"); + + checkStyleTag("@media not screen, print and (orientation: doesNotExist), all {}", + "@media not screen, all {\n}\n"); + + assertThrows(CSSParseException.class, () -> checkStyleTag("@media notValid screen {}", "")); + + assertThrows(CSSParseException.class, () -> checkStyleTag("@media doesNotExist {}", "")); + } + + private void checkStyleTag(String input, String expected) throws ScanException, PolicyException { + //Given + String taintedHtml = ""; + String expectedCleanHtml = ""; + + //When + CleanResults crDom = as.scan(taintedHtml, policy, AntiSamy.DOM); + CleanResults crSax = as.scan(taintedHtml, policy, AntiSamy.SAX); + + //Then + assertEquals(expectedCleanHtml, crDom.getCleanHTML()); + assertEquals(expectedCleanHtml, crSax.getCleanHTML()); + } } From 000457cfa4ba1d1ee5228ded8d7d55668cfbd310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Tue, 4 Feb 2025 12:57:09 +0100 Subject: [PATCH 2/8] fix(gh-552): failing test due to missing literal in policy --- src/main/resources/antisamy.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/antisamy.xml b/src/main/resources/antisamy.xml index 91c1313..c7fcbf1 100644 --- a/src/main/resources/antisamy.xml +++ b/src/main/resources/antisamy.xml @@ -2755,6 +2755,9 @@ + + + From 5a4a138344015b1aa1952f1ac8e34a92ffe97f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Wed, 5 Feb 2025 12:22:10 +0100 Subject: [PATCH 3/8] test(gh-552): add some more test cases for abbreviated syntax --- src/main/resources/antisamy.xml | 8 ++++++++ .../owasp/validator/html/test/AntiSamyTest.java | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/main/resources/antisamy.xml b/src/main/resources/antisamy.xml index c7fcbf1..a375ff5 100644 --- a/src/main/resources/antisamy.xml +++ b/src/main/resources/antisamy.xml @@ -2794,6 +2794,9 @@ + + + @@ -2914,6 +2917,8 @@ + + @@ -2968,6 +2973,9 @@ + + + diff --git a/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java b/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java index 706484c..6c07825 100644 --- a/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java +++ b/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java @@ -2775,6 +2775,21 @@ public void testGithubIssue552() throws ScanException, PolicyException { checkStyleTag("@media not screen, print and (orientation: doesNotExist), all {}", "@media not screen, all {\n}\n"); + checkStyleTag("@media (min-width: 500.0px) {\n}\n", + "@media all and (min-width: 500.0px) {\n}\n"); + + checkStyleTag("@media (grid) {\n}\n", + "@media all and (grid) {\n}\n"); + + checkStyleTag("@media (monochrome) {\n}\n", + "@media all and (monochrome) {\n}\n"); + + checkStyleTag("@media (monochrome: 2) {\n}\n", + "@media all and (monochrome: 2) {\n}\n"); + + checkStyleTag("@media (color-index) {\n}\n", + "@media all and (color-index) {\n}\n"); + assertThrows(CSSParseException.class, () -> checkStyleTag("@media notValid screen {}", "")); assertThrows(CSSParseException.class, () -> checkStyleTag("@media doesNotExist {}", "")); From ebd23ee22a2b46c8f3b9078bd7555b0b23743916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Mon, 10 Feb 2025 10:54:51 +0100 Subject: [PATCH 4/8] refactor(gh-552): move new policy rules from default policy to anythinggoes --- src/main/resources/antisamy-anythinggoes.xml | 466 ++++++++++++++++++ src/main/resources/antisamy.xml | 468 ------------------- 2 files changed, 466 insertions(+), 468 deletions(-) diff --git a/src/main/resources/antisamy-anythinggoes.xml b/src/main/resources/antisamy-anythinggoes.xml index 1c3b330..4366991 100644 --- a/src/main/resources/antisamy-anythinggoes.xml +++ b/src/main/resources/antisamy-anythinggoes.xml @@ -97,6 +97,8 @@ + + @@ -2612,6 +2614,470 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/antisamy.xml b/src/main/resources/antisamy.xml index a375ff5..43c1b86 100644 --- a/src/main/resources/antisamy.xml +++ b/src/main/resources/antisamy.xml @@ -101,13 +101,10 @@ - - - @@ -2719,471 +2716,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 524b38f9267d3a3f5cd3ca22b19152d1ced9a7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Mon, 10 Feb 2025 10:55:45 +0100 Subject: [PATCH 5/8] test(gh-552): default policy and extend it accordingly --- .../validator/html/test/AntiSamyTest.java | 76 +++++++++++++++---- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java b/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java index 6c07825..c43ac57 100644 --- a/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java +++ b/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java @@ -2760,42 +2760,86 @@ public void testGithubIssue546FaultyPercentagesGetFilteredByRegex() throws ScanE @Test public void testGithubIssue552() throws ScanException, PolicyException { + Pattern positiveLength = Pattern.compile("((\\+)?0|(\\+)?([0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?)(rem|vw|vh|em|ex|px|in|cm|mm|pt|pc))"); + Pattern integer = Pattern.compile("([-+])?[0-9]+"); + Property minWidth = new Property("_mediafeature_min-width", + Collections.singletonList(positiveLength), + Collections.emptyList(), + Collections.emptyList(), + "", + "remove"); + Property maxWidth = new Property("_mediafeature_max-width", + Collections.singletonList(positiveLength), + Collections.emptyList(), + Collections.emptyList(), + "", + "remove"); + Property color = new Property("_mediafeature_color", + Collections.singletonList(integer), + Collections.singletonList(""), + Collections.emptyList(), + "", + "remove"); + Property orientation = new Property("_mediafeature_orientation", + Collections.emptyList(), + Arrays.asList("portrait", "landscape"), + Collections.emptyList(), + "", + "remove"); + Property grid = new Property("_mediafeature_grid", + Collections.emptyList(), + Arrays.asList("", "-1", "-0", "0", "1"), + Collections.emptyList(), + "", + "remove"); + Property monochrome = new Property("_mediafeature_monochrome", + Collections.singletonList(integer), + Collections.singletonList(""), + Collections.emptyList(), + "", + "remove"); + checkStyleTag("@media screen {}", - "@media screen {\n}\n"); + "@media screen {\n}\n", + policy); checkStyleTag("@media screen,print {}", - "@media screen, print {\n}\n"); + "@media screen, print {\n}\n", + policy); checkStyleTag("@media only screen and (max-width: 639px) and (min-width: 300px) {}", - "@media only screen and (max-width: 639.0px) and (min-width: 300.0px) {\n}\n"); + "@media only screen and (max-width: 639.0px) and (min-width: 300.0px) {\n}\n", + this.policy.addCssProperty(minWidth).addCssProperty(maxWidth)); checkStyleTag("@media not screen, screen and (color), print and (orientation: portrait) {}", - "@media not screen, screen and (color), print and (orientation: portrait) {\n}\n"); + "@media not screen, screen and (color), print and (orientation: portrait) {\n}\n", + policy.addCssProperty(color).addCssProperty(orientation)); checkStyleTag("@media not screen, print and (orientation: doesNotExist), all {}", - "@media not screen, all {\n}\n"); + "@media not screen, all {\n}\n", + policy.addCssProperty(orientation)); checkStyleTag("@media (min-width: 500.0px) {\n}\n", - "@media all and (min-width: 500.0px) {\n}\n"); + "@media all and (min-width: 500.0px) {\n}\n", + policy.addCssProperty(minWidth)); checkStyleTag("@media (grid) {\n}\n", - "@media all and (grid) {\n}\n"); + "@media all and (grid) {\n}\n", + policy.addCssProperty(grid)); checkStyleTag("@media (monochrome) {\n}\n", - "@media all and (monochrome) {\n}\n"); + "@media all and (monochrome) {\n}\n", + policy.addCssProperty(monochrome)); checkStyleTag("@media (monochrome: 2) {\n}\n", - "@media all and (monochrome: 2) {\n}\n"); - - checkStyleTag("@media (color-index) {\n}\n", - "@media all and (color-index) {\n}\n"); - - assertThrows(CSSParseException.class, () -> checkStyleTag("@media notValid screen {}", "")); + "@media all and (monochrome: 2) {\n}\n", + policy.addCssProperty(monochrome)); - assertThrows(CSSParseException.class, () -> checkStyleTag("@media doesNotExist {}", "")); + assertThrows(CSSParseException.class, () -> checkStyleTag("@media notValid screen {}", "", policy)); + assertThrows(CSSParseException.class, () -> checkStyleTag("@media doesNotExist {}", "", policy)); } - private void checkStyleTag(String input, String expected) throws ScanException, PolicyException { + private void checkStyleTag(String input, String expected, Policy policy) throws ScanException, PolicyException { //Given String taintedHtml = ""; String expectedCleanHtml = ""; From af48b5a50ffe9a893ef89dace1b1ddb39862ca37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Mon, 10 Feb 2025 17:37:24 +0100 Subject: [PATCH 6/8] add(gh-552): handling of or, adds new test cases, refactors parsing --- .../org/owasp/validator/css/CssHandler.java | 7 +- .../org/owasp/validator/css/CssParser.java | 71 +++++++++++++++---- .../org/owasp/validator/css/CssValidator.java | 11 +-- .../media/CssMediaQueryLogicalOperator.java | 19 +++-- .../validator/css/media/CssMediaType.java | 19 +++-- src/main/resources/antisamy-anythinggoes.xml | 9 +++ .../validator/html/test/AntiSamyTest.java | 64 ++++++++++++----- 7 files changed, 152 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/owasp/validator/css/CssHandler.java b/src/main/java/org/owasp/validator/css/CssHandler.java index 038ec19..5bcca30 100644 --- a/src/main/java/org/owasp/validator/css/CssHandler.java +++ b/src/main/java/org/owasp/validator/css/CssHandler.java @@ -38,6 +38,7 @@ import org.owasp.validator.css.media.CssMediaFeature; import org.owasp.validator.css.media.CssMediaQuery; import org.owasp.validator.css.media.CssMediaQueryList; +import org.owasp.validator.css.media.CssMediaType; import org.owasp.validator.html.InternalPolicy; import org.owasp.validator.html.Policy; import org.owasp.validator.html.ScanException; @@ -546,7 +547,11 @@ public void startMedia(SACMediaList media) throws CSSException { } styleSheet.append(query.getMediaType()); for (CssMediaFeature feature : query.getMediaFeatures()) { - styleSheet.append(" and ("); + if (feature == query.getMediaFeatures().get(0) && query.getMediaType() == CssMediaType.IMPLIED_ALL) { + styleSheet.append("("); + } else { + styleSheet.append(" and ("); + } styleSheet.append(feature.getName()); if (feature.getExpression() != null) { styleSheet.append(": "); diff --git a/src/main/java/org/owasp/validator/css/CssParser.java b/src/main/java/org/owasp/validator/css/CssParser.java index 65f98cd..590f6ea 100644 --- a/src/main/java/org/owasp/validator/css/CssParser.java +++ b/src/main/java/org/owasp/validator/css/CssParser.java @@ -29,6 +29,7 @@ package org.owasp.validator.css; import static org.owasp.validator.css.media.CssMediaQueryLogicalOperator.AND; +import static org.owasp.validator.css.media.CssMediaQueryLogicalOperator.OR; import org.apache.batik.css.parser.CSSSACMediaList; import org.apache.batik.css.parser.LexicalUnits; @@ -110,7 +111,7 @@ protected CSSSACMediaList parseMediaList() { CssMediaQueryList mediaList = new CssMediaQueryList(); mediaList.append(parseMediaQuery()); - while (current == LexicalUnits.COMMA) { + while (hasAnotherMediaQuery()) { nextIgnoreSpaces(); mediaList.append(parseMediaQuery()); } @@ -118,31 +119,47 @@ protected CSSSACMediaList parseMediaList() { return mediaList; } + private boolean hasAnotherMediaQuery() { + return current == LexicalUnits.COMMA || (current == LexicalUnits.IDENTIFIER && scanner.getStringValue().equals(OR.toString())); + } + protected CssMediaQuery parseMediaQuery() { CssMediaQuery query = new CssMediaQuery(); + CssMediaType mediaType = null; + CssMediaQueryLogicalOperator logicalOperator = null; switch (current) { case LexicalUnits.LEFT_BRACE: - query.setMediaType(CssMediaType.ALL); - query.addMediaFeature(parseMediaFeature()); + mediaType = CssMediaType.IMPLIED_ALL; break; case LexicalUnits.IDENTIFIER: - final CssMediaQueryLogicalOperator logicalOperator = CssMediaQueryLogicalOperator.parse(scanner.getStringValue()); + logicalOperator = CssMediaQueryLogicalOperator.parse(scanner.getStringValue()); if (logicalOperator != null) { - query.setLogicalOperator(logicalOperator); - if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) { - throw createCSSParseException("identifier"); + switch (logicalOperator) { + case ONLY: + parseLogicalOperatorOnly(); + mediaType = parseMediaType(); + break; + case NOT: + mediaType = parseLogicalOperatorNot(); + break; + case AND: + case OR: + case COMMA: + throw createCSSParseException("identifier"); } + } else { + mediaType = parseMediaType(); } - final CssMediaType mediaType = CssMediaType.parse(scanner.getStringValue()); - if (mediaType == null) { - throw createCSSParseException("identifier"); - } - query.setMediaType(mediaType); - nextIgnoreSpaces(); break; default: throw createCSSParseException("identifier"); } + query.setMediaType(mediaType); + query.setLogicalOperator(logicalOperator); + + if (mediaType == CssMediaType.IMPLIED_ALL) { + query.addMediaFeature(parseMediaFeature()); + } while (current == LexicalUnits.IDENTIFIER && CssMediaQueryLogicalOperator.parse(scanner.getStringValue()) == AND) { nextIgnoreSpaces(); @@ -151,6 +168,32 @@ protected CssMediaQuery parseMediaQuery() { return query; } + private CssMediaType parseMediaType() { + CssMediaType mediaType; + mediaType = CssMediaType.parse(scanner.getStringValue()); + if (mediaType == null) { + throw createCSSParseException("identifier"); + } + nextIgnoreSpaces(); + return mediaType; + } + + private CssMediaType parseLogicalOperatorNot() { + CssMediaType mediaType; + if (nextIgnoreSpaces() == LexicalUnits.IDENTIFIER) { + mediaType = parseMediaType(); + } else { + mediaType = CssMediaType.IMPLIED_ALL; + } + return mediaType; + } + + private void parseLogicalOperatorOnly() { + if (nextIgnoreSpaces() != LexicalUnits.IDENTIFIER) { + throw createCSSParseException("identifier"); + } + } + protected CssMediaFeature parseMediaFeature() { if (current != LexicalUnits.LEFT_BRACE) { throw createCSSParseException("'(' expected."); @@ -172,7 +215,7 @@ protected CssMediaFeature parseMediaFeature() { exp = parseTerm(null); } if (current != LexicalUnits.RIGHT_BRACE) { - throw createCSSParseException("right.brace"); + throw createCSSParseException("')' expected."); } nextIgnoreSpaces(); diff --git a/src/main/java/org/owasp/validator/css/CssValidator.java b/src/main/java/org/owasp/validator/css/CssValidator.java index e23cc4a..fb1bd21 100644 --- a/src/main/java/org/owasp/validator/css/CssValidator.java +++ b/src/main/java/org/owasp/validator/css/CssValidator.java @@ -37,7 +37,6 @@ import org.owasp.validator.html.Policy; import org.owasp.validator.html.ScanException; import org.owasp.validator.html.model.AntiSamyPattern; -import org.owasp.validator.html.model.Attribute; import org.owasp.validator.html.model.Property; import org.owasp.validator.html.util.HTMLEntityEncoder; import org.w3c.css.sac.AttributeCondition; @@ -420,13 +419,17 @@ public String lexicalValueToString(LexicalUnit lu) { */ public boolean isValidMediaQuery(CssMediaQuery mediaQuery) { // check mediaType against allowed media-HTML-Attribute - Attribute mediaAttribute = policy.getTagByLowercaseName("style").getAttributeByName("media"); - if (mediaAttribute == null) { + Property mediatype = policy.getPropertyByName("_mediatype"); + if (mediatype == null) { return false; } String mediaTypeString = mediaQuery.getMediaType().toString().toLowerCase(); - boolean isValidMediaType = mediaAttribute.containsAllowedValue(mediaTypeString) || mediaAttribute.matchesAllowedExpression(mediaTypeString); + boolean isValidMediaType = mediatype.getAllowedValues() + .contains(mediaTypeString) || mediatype.getAllowedRegExp() + .stream() + .anyMatch(pattern -> pattern.matcher(mediaTypeString) + .matches()); if (!isValidMediaType) { return false; } diff --git a/src/main/java/org/owasp/validator/css/media/CssMediaQueryLogicalOperator.java b/src/main/java/org/owasp/validator/css/media/CssMediaQueryLogicalOperator.java index adbad04..58d1d60 100644 --- a/src/main/java/org/owasp/validator/css/media/CssMediaQueryLogicalOperator.java +++ b/src/main/java/org/owasp/validator/css/media/CssMediaQueryLogicalOperator.java @@ -1,18 +1,25 @@ package org.owasp.validator.css.media; public enum CssMediaQueryLogicalOperator { - AND, NOT, ONLY, OR; + AND("and"), NOT("not"), ONLY("only"), OR("or"), COMMA(","); + + public final String label; + + CssMediaQueryLogicalOperator(String label) { + this.label = label; + } @Override public String toString() { - return super.toString().toLowerCase(); + return label; } public static CssMediaQueryLogicalOperator parse(String operator) { - try { - return CssMediaQueryLogicalOperator.valueOf(operator.toUpperCase()); - } catch (IllegalArgumentException e) { - return null; + for (CssMediaQueryLogicalOperator element : values()) { + if (element.label.equalsIgnoreCase(operator)) { + return element; + } } + return null; } } diff --git a/src/main/java/org/owasp/validator/css/media/CssMediaType.java b/src/main/java/org/owasp/validator/css/media/CssMediaType.java index 3dd9ab7..8f70a84 100644 --- a/src/main/java/org/owasp/validator/css/media/CssMediaType.java +++ b/src/main/java/org/owasp/validator/css/media/CssMediaType.java @@ -1,18 +1,25 @@ package org.owasp.validator.css.media; public enum CssMediaType { - ALL, PRINT, SCREEN; + ALL("all"), PRINT("print"), SCREEN("screen"), IMPLIED_ALL(""); + + public final String label; + + CssMediaType(String label) { + this.label = label; + } @Override public String toString() { - return super.toString().toLowerCase(); + return label; } public static CssMediaType parse(String mediaType) { - try { - return CssMediaType.valueOf(mediaType.toUpperCase()); - } catch (IllegalArgumentException e) { - return null; + for (CssMediaType element : values()) { + if (element.toString().equalsIgnoreCase(mediaType)) { + return element; + } } + return null; } } diff --git a/src/main/resources/antisamy-anythinggoes.xml b/src/main/resources/antisamy-anythinggoes.xml index 4366991..52a39a2 100644 --- a/src/main/resources/antisamy-anythinggoes.xml +++ b/src/main/resources/antisamy-anythinggoes.xml @@ -2625,6 +2625,15 @@ + + + + + + + + + diff --git a/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java b/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java index c43ac57..0dcf7a2 100644 --- a/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java +++ b/src/test/java/org/owasp/validator/html/test/AntiSamyTest.java @@ -2762,6 +2762,12 @@ public void testGithubIssue546FaultyPercentagesGetFilteredByRegex() throws ScanE public void testGithubIssue552() throws ScanException, PolicyException { Pattern positiveLength = Pattern.compile("((\\+)?0|(\\+)?([0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?)(rem|vw|vh|em|ex|px|in|cm|mm|pt|pc))"); Pattern integer = Pattern.compile("([-+])?[0-9]+"); + Property mediaType = new Property("_mediatype", + Collections.emptyList(), + Arrays.asList("", "all", "print", "screen"), + Collections.emptyList(), + "", + "remove"); Property minWidth = new Property("_mediafeature_min-width", Collections.singletonList(positiveLength), Collections.emptyList(), @@ -2801,39 +2807,63 @@ public void testGithubIssue552() throws ScanException, PolicyException { checkStyleTag("@media screen {}", "@media screen {\n}\n", - policy); + policy.addCssProperty(mediaType)); checkStyleTag("@media screen,print {}", "@media screen, print {\n}\n", - policy); + policy.addCssProperty(mediaType)); checkStyleTag("@media only screen and (max-width: 639px) and (min-width: 300px) {}", "@media only screen and (max-width: 639.0px) and (min-width: 300.0px) {\n}\n", - this.policy.addCssProperty(minWidth).addCssProperty(maxWidth)); + policy.addCssProperty(mediaType).addCssProperty(minWidth).addCssProperty(maxWidth)); checkStyleTag("@media not screen, screen and (color), print and (orientation: portrait) {}", "@media not screen, screen and (color), print and (orientation: portrait) {\n}\n", - policy.addCssProperty(color).addCssProperty(orientation)); + policy.addCssProperty(mediaType).addCssProperty(color).addCssProperty(orientation)); checkStyleTag("@media not screen, print and (orientation: doesNotExist), all {}", "@media not screen, all {\n}\n", - policy.addCssProperty(orientation)); + policy.addCssProperty(mediaType).addCssProperty(orientation)); - checkStyleTag("@media (min-width: 500.0px) {\n}\n", - "@media all and (min-width: 500.0px) {\n}\n", - policy.addCssProperty(minWidth)); + checkStyleTag("@media (min-width: 500.0px) {}", + "@media (min-width: 500.0px) {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(minWidth)); - checkStyleTag("@media (grid) {\n}\n", - "@media all and (grid) {\n}\n", - policy.addCssProperty(grid)); + checkStyleTag("@media (grid) {}", + "@media (grid) {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(grid)); - checkStyleTag("@media (monochrome) {\n}\n", - "@media all and (monochrome) {\n}\n", - policy.addCssProperty(monochrome)); + checkStyleTag("@media (monochrome) {}", + "@media (monochrome) {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(monochrome)); - checkStyleTag("@media (monochrome: 2) {\n}\n", - "@media all and (monochrome: 2) {\n}\n", - policy.addCssProperty(monochrome)); + checkStyleTag("@media (monochrome: 2) {}", + "@media (monochrome: 2) {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(monochrome)); + + checkStyleTag("@media screen and (max-width: 639px) or only print {}", + "@media screen and (max-width: 639.0px), only print {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(maxWidth)); + + checkStyleTag("@media print or (max-width: 639px) or only print {}", + "@media print, (max-width: 639.0px), only print {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(maxWidth)); + + checkStyleTag("@media print or not (max-width: 639px), not print {}", + "@media print, not (max-width: 639.0px), not print {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(maxWidth)); + + checkStyleTag("@media only print or not (max-width: 639px) and (min-width: 500px), not print {}", + "@media only print, not (max-width: 639.0px) and (min-width: 500.0px), not print {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(maxWidth).addCssProperty(minWidth)); + + checkStyleTag("@media only print or not (max-width: 639px) and (min-width: 500px), not screen {}", + "@media only print, not screen {\n}\n", + policy.addCssProperty(mediaType).addCssProperty(maxWidth)); + + checkStyleTag("@media screen {*{color: red;notAllowed: nope}}", + "@media screen {\n* {\n\tcolor: red;\n}\n}\n", + policy.addCssProperty(mediaType)); assertThrows(CSSParseException.class, () -> checkStyleTag("@media notValid screen {}", "", policy)); assertThrows(CSSParseException.class, () -> checkStyleTag("@media doesNotExist {}", "", policy)); From ac32f5feb0c9f5eabf0698aa3e558013799f7fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Mon, 10 Feb 2025 17:51:52 +0100 Subject: [PATCH 7/8] refactor(gh-552): make Java 7 compliant --- .../java/org/owasp/validator/css/CssValidator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/owasp/validator/css/CssValidator.java b/src/main/java/org/owasp/validator/css/CssValidator.java index fb1bd21..934ef17 100644 --- a/src/main/java/org/owasp/validator/css/CssValidator.java +++ b/src/main/java/org/owasp/validator/css/CssValidator.java @@ -425,11 +425,11 @@ public boolean isValidMediaQuery(CssMediaQuery mediaQuery) { } String mediaTypeString = mediaQuery.getMediaType().toString().toLowerCase(); - boolean isValidMediaType = mediatype.getAllowedValues() - .contains(mediaTypeString) || mediatype.getAllowedRegExp() - .stream() - .anyMatch(pattern -> pattern.matcher(mediaTypeString) - .matches()); + boolean isRegExpAllowed = true; + for (Pattern pattern : mediatype.getAllowedRegExp()) { + isRegExpAllowed &= pattern.matcher(mediaTypeString).matches(); + } + boolean isValidMediaType = mediatype.getAllowedValues().contains(mediaTypeString) || isRegExpAllowed; if (!isValidMediaType) { return false; } From accd82255fcb2a8736876d1fe4520703c2b10f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonah=20Kl=C3=B6ckner?= Date: Mon, 10 Feb 2025 17:56:02 +0100 Subject: [PATCH 8/8] fix(gh-552): change logical operator to OR for regex pattern matching --- src/main/java/org/owasp/validator/css/CssValidator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/owasp/validator/css/CssValidator.java b/src/main/java/org/owasp/validator/css/CssValidator.java index 934ef17..8f6c07b 100644 --- a/src/main/java/org/owasp/validator/css/CssValidator.java +++ b/src/main/java/org/owasp/validator/css/CssValidator.java @@ -425,9 +425,9 @@ public boolean isValidMediaQuery(CssMediaQuery mediaQuery) { } String mediaTypeString = mediaQuery.getMediaType().toString().toLowerCase(); - boolean isRegExpAllowed = true; + boolean isRegExpAllowed = false; for (Pattern pattern : mediatype.getAllowedRegExp()) { - isRegExpAllowed &= pattern.matcher(mediaTypeString).matches(); + isRegExpAllowed |= pattern.matcher(mediaTypeString).matches(); } boolean isValidMediaType = mediatype.getAllowedValues().contains(mediaTypeString) || isRegExpAllowed; if (!isValidMediaType) {