diff --git a/Changelog.md b/Changelog.md index 9bce73f..d3838f3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,12 @@ A brief description of what changes project contains +## May 6, 2024 + +#### v1.2.9 + +- Fixed vulnerability issue related to strAttrs and children. + ## April 23, 2024 #### v1.2.8 diff --git a/pom.xml b/pom.xml index 3ff59ce..2b2b6aa 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.contentstack.sdk utils - 1.2.8 + 1.2.9 jar Contentstack-utils Java Utils SDK for Contentstack Content Delivery API, Contentstack is a headless CMS diff --git a/src/main/java/com/contentstack/utils/render/DefaultOption.java b/src/main/java/com/contentstack/utils/render/DefaultOption.java index e384698..35dae2a 100644 --- a/src/main/java/com/contentstack/utils/render/DefaultOption.java +++ b/src/main/java/com/contentstack/utils/render/DefaultOption.java @@ -6,6 +6,8 @@ import com.contentstack.utils.node.MarkType; import org.apache.commons.text.StringEscapeUtils; import org.json.JSONObject; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; import java.util.*; @@ -101,67 +103,70 @@ private String escapeInjectHtml(JSONObject nodeObj, String nodeType) { public String renderNode(String nodeType, JSONObject nodeObject, NodeCallback callback) { String strAttrs = strAttrs(nodeObject); String children = callback.renderChildren(nodeObject.optJSONArray("children")); + // Jsoup sanitization + Document sanitizedChildren = Jsoup.parse(children); + String cleanChildren = sanitizedChildren.body().html(); switch (nodeType) { case "p": - return "" + children + "

"; + return "" + cleanChildren + "

"; case "a": - return "" + children + ""; + return "" + cleanChildren + ""; case "img": String assetLink = getNodeStr(nodeObject, "asset-link"); if (!assetLink.isEmpty()) { JSONObject attrs = nodeObject.optJSONObject("attrs"); if (attrs.has("link")) { - return "" + "" + children + ""; + return "" + "" + cleanChildren + ""; } - return "" + children; + return "" + cleanChildren; } - return "" + children; + return "" + cleanChildren; case "embed": - return ""; + return ""; case "h1": - return "" + children + ""; + return "" + cleanChildren + ""; case "h2": - return "" + children + ""; + return "" + cleanChildren + ""; case "h3": - return "" + children + ""; + return "" + cleanChildren + ""; case "h4": - return "" + children + ""; + return "" + cleanChildren + ""; case "h5": - return "" + children + ""; + return "" + cleanChildren + ""; case "h6": - return "" + children + ""; + return "" + cleanChildren + ""; case "ol": - return "" + children + ""; + return "" + cleanChildren + ""; case "ul": - return "" + children + ""; + return "" + cleanChildren + ""; case "li": - return "" + children + ""; + return "" + cleanChildren + ""; case "hr": return ""; case "table": - return "" + children + "
"; + return "" + cleanChildren + "
"; case "thead": - return "" + children + ""; + return "" + cleanChildren + ""; case "tbody": - return "" + children + ""; + return "" + cleanChildren + ""; case "tfoot": - return "" + children + ""; + return "" + cleanChildren + ""; case "tr": - return "" + children + ""; + return "" + cleanChildren + ""; case "th": - return "" + children + ""; + return "" + cleanChildren + ""; case "td": - return "" + children + ""; + return "" + cleanChildren + ""; case "blockquote": - return "" + children + ""; + return "" + cleanChildren + ""; case "code": - return "" + children + ""; + return "" + cleanChildren + ""; case "reference": return ""; case "fragment": - return "" + children + ""; + return "" + cleanChildren + ""; default: - return children; + return cleanChildren; } } @@ -182,6 +187,16 @@ String strAttrs(JSONObject nodeObject) { for (String key : attrsObject.keySet()) { Object objValue = attrsObject.opt(key); String value = objValue.toString(); + + StringBuilder escapedValue = new StringBuilder(); + for (char ch : value.toCharArray()) { + if (ch == '&' || ch == '<' || ch == '>' || ch == '"' || ch == '\'') { + escapedValue.append("&#").append((int) ch).append(';'); + } else { + escapedValue.append(ch); + } + } + value = escapedValue.toString(); // If style is available, do styling calculations if (Objects.equals(key, "style")) { String resultStyle = stringifyStyles(attrsObject.optJSONObject("style"));