@@ -238,6 +238,28 @@ public static void noSpace(String string) throws JSONException {
238238 }
239239 }
240240
241+ /**
242+ * Throw an exception if the string contains an XML metacharacter
243+ * ({@code < > & " ' /}). Used by {@link #toString(Object)} to reject JSON
244+ * keys that would otherwise be emitted verbatim between {@code <} and
245+ * {@code >} and could break out of the tag context (element injection,
246+ * CWE-91; see issue #1071).
247+ *
248+ * @param string the candidate element name
249+ * @throws JSONException if {@code string} contains an XML metacharacter
250+ */
251+ static void noXmlMetachars (String string ) throws JSONException {
252+ int length = string .length ();
253+ for (int i = 0 ; i < length ; i ++) {
254+ char c = string .charAt (i );
255+ if (c == '<' || c == '>' || c == '&'
256+ || c == '"' || c == '\'' || c == '/' ) {
257+ throw new JSONException ("'" + string
258+ + "' contains an XML metacharacter and may not be used as an element name." );
259+ }
260+ }
261+ }
262+
241263 /**
242264 * Scan the content following the named tag, attaching it to the context.
243265 *
@@ -974,6 +996,10 @@ private static String toString(final Object object, final String tagName, final
974996 JSONObject jo ;
975997 String string ;
976998
999+ if (tagName != null ) {
1000+ noXmlMetachars (tagName );
1001+ }
1002+
9771003 if (object instanceof JSONObject ) {
9781004
9791005 // Emit <tagName>
@@ -992,6 +1018,9 @@ private static String toString(final Object object, final String tagName, final
9921018 // don't use the new entrySet accessor to maintain Android Support
9931019 jo = (JSONObject ) object ;
9941020 for (final String key : jo .keySet ()) {
1021+ if (!key .equals (config .getcDataTagName ())) {
1022+ noXmlMetachars (key );
1023+ }
9951024 Object value = jo .opt (key );
9961025 if (value == null ) {
9971026 value = "" ;
0 commit comments