CVE-2019-12741: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: XSS exists in the HAPI FHIR testpage overlay module of the HAPI FHIR library before 3.8.0. The attack involves unsanitized HTTP parameters being output in a form page, allowing attackers to leak cookies and other sensitive information from ca/uhn/fhir/to/BaseController.java via a specially crafted URL. (This module is not generally used in production systems so the attack surface is expected to be low, but affected systems are recommended to upgrade immediately.)
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: 6.1
Published: 2019-06-05T15:29Z
Repository: https://github.com/jamesagnew/hapi-fhir
Language: XML
Files changed: hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java, src/changes/changes.xml
Commit date: 2019-05-02 08:13:22 -0400
Commit message: Fix a potential security vulneability in the testpage overlay

Diff: diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
index 979c83148..ad48f5a2b 100644
--- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
+++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
@@ -30,11 +30,10 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
 import org.hl7.fhir.instance.model.api.IBaseResource;
 import org.hl7.fhir.instance.model.api.IDomainResource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.ui.ModelMap;
 import org.thymeleaf.ITemplateEngine;
-import org.thymeleaf.TemplateEngine;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
@@ -61,18 +60,18 @@ public class BaseController {
 	protected IBaseResource addCommonParams(HttpServletRequest theServletRequest, final HomeRequest theRequest, final ModelMap theModel) {
 		final String serverId = theRequest.getServerIdWithDefault(myConfig);
 		final String serverBase = theRequest.getServerBase(theServletRequest, myConfig);
 		final String serverName = theRequest.getServerName(myConfig);
 		final String apiKey = theRequest.getApiKey(theServletRequest, myConfig);
-		theModel.put("serverId", serverId);
-		theModel.put("base", serverBase);
-		theModel.put("baseName", serverName);
-		theModel.put("apiKey", apiKey);
-		theModel.put("resourceName", defaultString(theRequest.getResource()));
-		theModel.put("encoding", theRequest.getEncoding());
-		theModel.put("pretty", theRequest.getPretty());
-		theModel.put("_summary", theRequest.get_summary());
+		theModel.put("serverId", sanitizeInput(serverId));
+		theModel.put("base", sanitizeInput(serverBase));
+		theModel.put("baseName", sanitizeInput(serverName));
+		theModel.put("apiKey", sanitizeInput(apiKey));
+		theModel.put("resourceName", sanitizeInput(defaultString(theRequest.getResource())));
+		theModel.put("encoding", sanitizeInput(theRequest.getEncoding()));
+		theModel.put("pretty", sanitizeInput(theRequest.getPretty()));
+		theModel.put("_summary", sanitizeInput(theRequest.get_summary()));
 		theModel.put("serverEntries", myConfig.getIdToServerName());
 
 		return loadAndAddConf(theServletRequest, theRequest, theModel);
 	}
 
@@ -305,11 +304,10 @@ public class BaseController {
 				break;
 		}
 		throw new IllegalStateException("Unknown version: " + theRequest.getFhirVersion(myConfig));
 	}
 
-
 	private IResource loadAndAddConfDstu2(HttpServletRequest theServletRequest, final HomeRequest theRequest, final ModelMap theModel) {
 		CaptureInterceptor interceptor = new CaptureInterceptor();
 		GenericClient client = theRequest.newClient(theServletRequest, getContext(theRequest), myConfig, interceptor);
 
 		ca.uhn.fhir.model.dstu2.resource.Conformance conformance;
@@ -744,6 +742,23 @@ public class BaseController {
 //
 //		}
 
 	}
 
+	private static String sanitizeInput(String theString) {
+		String retVal = theString;
+		if (retVal != null) {
+			for (int i = 0; i < retVal.length(); i++) {
+				char nextChar = retVal.charAt(i);
+				switch (nextChar) {
+					case '\'':
+					case '"':
+					case '<':
+					case '>':
+						retVal = retVal.replace(nextChar, '_');
+				}
+			}
+		}
+		return retVal;
+	}
+
 }
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 06d3ba70d..849b7e4e3 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -5,10 +5,15 @@
 		<author>James Agnew</author>
 		<title>HAPI FHIR Changelog</title>
 	</properties>
 	<body>
 		<release version="3.8.0" date="TBD" description="Hippo">
+			<action type="fix">
+				A potential security vulnerability in the hapi-fhir-testpage-overlay project was corrected: A URL
+				parameter was not being correctly escaped, leading to a potential XSS vulnerabnility. A big thanks to
+				Mudit Punia and Dushyant Garg for reporting this.
+			</action>
 			<action type="add">
 				The version of a few dependencies have been bumped to the
 				latest versions (dependent HAPI modules listed in brackets):
 				<![CDATA[
 				<ul>

Vulnerable code: import org.thymeleaf.TemplateEngine;
		theModel.put("serverId", serverId);
		theModel.put("base", serverBase);
		theModel.put("baseName", serverName);
		theModel.put("apiKey", apiKey);
		theModel.put("resourceName", defaultString(theRequest.getResource()));
		theModel.put("encoding", theRequest.getEncoding());
		theModel.put("pretty", theRequest.getPretty());
		theModel.put("_summary", theRequest.get_summary());

Fixed code: 		theModel.put("serverId", sanitizeInput(serverId));
		theModel.put("base", sanitizeInput(serverBase));
		theModel.put("baseName", sanitizeInput(serverName));
		theModel.put("apiKey", sanitizeInput(apiKey));
		theModel.put("resourceName", sanitizeInput(defaultString(theRequest.getResource())));
		theModel.put("encoding", sanitizeInput(theRequest.getEncoding()));
		theModel.put("pretty", sanitizeInput(theRequest.getPretty()));
		theModel.put("_summary", sanitizeInput(theRequest.get_summary()));
	private static String sanitizeInput(String theString) {
		String retVal = theString;
		if (retVal != null) {
			for (int i = 0; i < retVal.length(); i++) {
				char nextChar = retVal.charAt(i);
				switch (nextChar) {
					case '\'':
					case '"':
					case '<':
					case '>':
						retVal = retVal.replace(nextChar, '_');
				}
			}
		}
		return retVal;
	}

			<action type="fix">
				A potential security vulnerability in the hapi-fhir-testpage-overlay project was corrected: A URL
				parameter was not being correctly escaped, leading to a potential XSS vulnerabnility. A big thanks to
				Mudit Punia and Dushyant Garg for reporting this.
			</action>