diff --git a/src/main/java/org/json/XML.java b/src/main/java/org/json/XML.java
index 7e4b0bb0c..becf0e6e1 100644
--- a/src/main/java/org/json/XML.java
+++ b/src/main/java/org/json/XML.java
@@ -158,7 +158,7 @@ public static String escape(String string) {
* @param cp code point to test
* @return true if the code point is not valid for an XML
*/
- private static boolean mustEscape(int cp) {
+ static boolean mustEscape(int cp) {
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets
*
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
diff --git a/src/main/java/org/json/XMLTokener.java b/src/main/java/org/json/XMLTokener.java
index dad2e2897..dc90f84d4 100644
--- a/src/main/java/org/json/XMLTokener.java
+++ b/src/main/java/org/json/XMLTokener.java
@@ -167,6 +167,9 @@ static String unescapeEntity(String e) throws JSONException {
int cp = (e.charAt(1) == 'x' || e.charAt(1) == 'X')
? parseHexEntity(e)
: parseDecimalEntity(e);
+ if (XML.mustEscape(cp)) {
+ throw new JSONException("Invalid numeric character reference: " + e.substring(1) + ";");
+ }
return new String(new int[] {cp}, 0, 1);
}
Character knownEntity = entity.get(e);
diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java
index 25b0a0e42..589536fd2 100644
--- a/src/test/java/org/json/junit/XMLTest.java
+++ b/src/test/java/org/json/junit/XMLTest.java
@@ -1468,6 +1468,42 @@ public void testInvalidHexEntityThrowsJSONException() {
XML.toJSONObject(xmlStr);
}
+ /**
+ * Tests that out-of-range hex entities throw JSONException rather than an uncaught runtime exception.
+ */
+ @Test(expected = JSONException.class)
+ public void testOutOfRangeHexEntityThrowsJSONException() {
+ String xmlStr = "";
+ XML.toJSONObject(xmlStr);
+ }
+
+ /**
+ * Tests that out-of-range decimal entities throw JSONException rather than an uncaught runtime exception.
+ */
+ @Test(expected = JSONException.class)
+ public void testOutOfRangeDecimalEntityThrowsJSONException() {
+ String xmlStr = "";
+ XML.toJSONObject(xmlStr);
+ }
+
+ /**
+ * Tests that surrogate code point entities throw JSONException.
+ */
+ @Test(expected = JSONException.class)
+ public void testSurrogateHexEntityThrowsJSONException() {
+ String xmlStr = "";
+ XML.toJSONObject(xmlStr);
+ }
+
+ /**
+ * Tests that out-of-range numeric entities in attribute values throw JSONException.
+ */
+ @Test(expected = JSONException.class)
+ public void testOutOfRangeHexEntityInAttributeThrowsJSONException() {
+ String xmlStr = "";
+ XML.toJSONObject(xmlStr);
+ }
+
/**
* Tests that valid decimal numeric entity A works correctly.
* Should decode to character 'A'.