CVE-2022-4396: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability was found in RDFlib pyrdfa3 and classified as problematic. This issue affects the function _get_option of the file pyRdfa/__init__.py. The manipulation leads to cross site scripting. The attack may be initiated remotely. The name of the patch is ffd1d62dd50d5f4190013b39cedcdfbd81f3ce3e. It is recommended to apply a patch to fix this issue. The identifier VDB-215249 was assigned to this vulnerability. NOTE: This vulnerability only affects products that are no longer supported by the maintainer.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 5.4
Published: 2022-12-10T12:15Z
Repository: https://github.com/RDFLib/pyrdfa3
Language: Python
Files changed: pyRdfa/__init__.py
Commit date: 2022-03-24 16:16:23 +0100
Commit message: xss changes

Diff: diff --git a/pyRdfa/__init__.py b/pyRdfa/__init__.py
index 71136bd..eae6db5 100644
--- a/pyRdfa/__init__.py
+++ b/pyRdfa/__init__.py
@@ -453,10 +453,20 @@ class pyRdfa :
 			raise e
 		except :
 			(type, value, traceback) = sys.exc_info()
 			raise FailedSource(value)
 
+	@staticmethod
+	def _validate_output_format(outputFormat):
+		"""
+		Malicious actors may create XSS style issues by using an illegal output format... better be careful
+		"""
+		# protection against possible malicious URL call
+		if outputFormat not in ["turtle", "n3", "xml", "pretty-xml", "nt", "json-ld"] :
+			outputFormat = "turtle"
+		return outputFormat
+		
 	####################################################################################################################
 	# Externally used methods
 	#
 	def graph_from_DOM(self, dom, graph = None, pgraph = None) :
 		"""
@@ -685,14 +695,16 @@ class pyRdfa :
 		@keyword rdfOutput: controls what happens in case an exception is raised. If the value is False, the caller is responsible handling it; otherwise a graph is returned with an error message included in the processor graph
 		@type rdfOutput: boolean
 		@return: a serialized RDF Graph
 		@rtype: string
 		"""
+		# protection against possible malicious URL call
+		outputFormat = pyRdfa._validate_output_format(outputFormat);
+
 		# This is better because it gives access to the various, non-standard serializations
 		# If it does not work because the extra are not installed, fall back to the standard
 		# rdlib distribution...
-
 		if rdflib.__version__ >= "3.0.0" :
 			graph = Graph()
 		else :
 			# We may need the extra utilities for older rdflib versions...
 			try :
@@ -879,19 +891,20 @@ def processURI(uri, outputFormat, form={}) :
 	#	os.environ['rdfaerror'] = 'true'
 
 	# This is really for testing purposes only, it is an unpublished flag to force RDF output no
 	# matter what
 	try :
-		graph = processor.rdf_from_source(input, outputFormat, rdfOutput = ("forceRDFOutput" in list(form.keys())) or not htmlOutput)
+		outputFormat = pyRdfa._validate_output_format(outputFormat);
 		if outputFormat == "n3" :
 			retval = 'Content-Type: text/rdf+n3; charset=utf-8\n'
 		elif outputFormat == "nt" or outputFormat == "turtle" :
 			retval = 'Content-Type: text/turtle; charset=utf-8\n'
 		elif outputFormat == "json-ld" or outputFormat == "json" :
 			retval = 'Content-Type: application/ld+json; charset=utf-8\n'
 		else :
 			retval = 'Content-Type: application/rdf+xml; charset=utf-8\n'
+		graph = processor.rdf_from_source(input, outputFormat, rdfOutput = ("forceRDFOutput" in list(form.keys())) or not htmlOutput)
 		retval += '\n'
 		retval += graph
 		return retval
 	except HTTPError :
 		(type,h,traceback) = sys.exc_info()
@@ -934,16 +947,16 @@ def processURI(uri, outputFormat, form={}) :
 		elif uri == "uploaded:" :
 			retval +="<dt>Uploaded file</dt>\n"
 		else :
 			retval +="<dt>URI received:</dt><dd><code>'%s'</code></dd>\n" % cgi.escape(uri)
 		if "host_language" in list(form.keys()) :
-			retval +="<dt>Media Type:</dt><dd>%s</dd>\n" % media_type
+			retval +="<dt>Media Type:</dt><dd>%s</dd>\n" % cgi.escape(media_type)
 		if "graph" in list(form.keys()) :
-			retval +="<dt>Requested graphs:</dt><dd>%s</dd>\n" % form.getfirst("graph").lower()
+			retval +="<dt>Requested graphs:</dt><dd>%s</dd>\n" % cgi.escape(form.getfirst("graph").lower())
 		else :
 			retval +="<dt>Requested graphs:</dt><dd>default</dd>\n"
 		retval +="<dt>Output serialization format:</dt><dd> %s</dd>\n" % outputFormat
-		if "space_preserve" in form : retval +="<dt>Space preserve:</dt><dd> %s</dd>\n" % form["space_preserve"].value
+		if "space_preserve" in form : retval +="<dt>Space preserve:</dt><dd> %s</dd>\n" % cgi.escape(form["space_preserve"].value)
 		retval +="</dl>\n"
 		retval +="</body>\n"
 		retval +="</html>\n"
 		return retval

Vulnerable code: 
		graph = processor.rdf_from_source(input, outputFormat, rdfOutput = ("forceRDFOutput" in list(form.keys())) or not htmlOutput)
			retval +="<dt>Media Type:</dt><dd>%s</dd>\n" % media_type
			retval +="<dt>Requested graphs:</dt><dd>%s</dd>\n" % form.getfirst("graph").lower()
		if "space_preserve" in form : retval +="<dt>Space preserve:</dt><dd> %s</dd>\n" % form["space_preserve"].value
Fixed code: 	@staticmethod
	def _validate_output_format(outputFormat):
		"""
		Malicious actors may create XSS style issues by using an illegal output format... better be careful
		"""
		# protection against possible malicious URL call
		if outputFormat not in ["turtle", "n3", "xml", "pretty-xml", "nt", "json-ld"] :
			outputFormat = "turtle"
		return outputFormat
		
		# protection against possible malicious URL call
		outputFormat = pyRdfa._validate_output_format(outputFormat);

		outputFormat = pyRdfa._validate_output_format(outputFormat);
		graph = processor.rdf_from_source(input, outputFormat, rdfOutput = ("forceRDFOutput" in list(form.keys())) or not htmlOutput)
			retval +="<dt>Media Type:</dt><dd>%s</dd>\n" % cgi.escape(media_type)
			retval +="<dt>Requested graphs:</dt><dd>%s</dd>\n" % cgi.escape(form.getfirst("graph").lower())
		if "space_preserve" in form : retval +="<dt>Space preserve:</dt><dd> %s</dd>\n" % cgi.escape(form["space_preserve"].value)