CVE-2021-32054 (C#, published 2021-05-14T21:15Z)
Description: value: Firely/Incendi Spark before 1.5.5-r4 lacks Content-Disposition headers in certain situations, which may cause crafted files to be delivered to clients such that they are rendered directly in a victim's web browser.
Severity: MEDIUM (CVSS v3 base score: 6.1)
Weakness: CWE-706 \u2014 Use of Incorrectly-Resolved Name or Reference
The product uses a name or reference to access a resource, but the name/reference resolves to a resource that is outside of the intended control sphere.
Repository: https://github.com/FirelyTeam/spark
Files changed:
src/Spark.Engine/Core/HttpHeaderName.cs
src/Spark.Engine/Extensions/HttpRequestFhirExtensions.cs
src/Spark.Engine/Formatters/NetCore/BinaryOutputFormatter.cs
src/Spark.Engine/Handlers/NetCore/FormatTypeHandler.cs
Commit message: refactor: Add constants for HTTP Header field names

Added constants for HTTP Header field names

Set Content-Disposition header to attachment for Binary requests


Vulnerable code:
                response.Headers.Add("ETag", ETag.Create(fhirResponse.Key.VersionId)?.ToString());
                response.Headers.Add("Location", location.OriginalString);
                    response.Headers.Add("Content-Location", location.OriginalString);
                        response.Headers.Add("Last-Modified", fhirResponse.Resource.Meta.LastUpdated.Value.ToString("R"));
                    if (context.Request.Headers.ContainsKey("Accept")) context.Request.Headers.Remove("Accept");
                        context.Request.Headers.Add("Accept", new StringValues(ContentType.JSON_CONTENT_HEADER));
                        context.Request.Headers.Add("Accept", new StringValues(ContentType.XML_CONTENT_HEADER));
                    context.Request.Headers.Add("X-Content-Type", contentType);

Fixed code:
﻿namespace Spark.Engine.Core
{
    internal static class HttpHeaderName
    {
        public const string ACCEPT = "Accept";
        public const string CONTENT_DISPOSITION = "Content-Disposition";
        public const string CONTENT_LOCATION = "Content-Location";
        public const string CONTENT_TYPE = "Content-Type";
        public const string ETAG = "ETag";
        public const string LOCATION = "Location";
        public const string LAST_MODIFIED = "Last-Modified";

        public const string X_CONTENT_TYPE = "X-Content-Type";
    }
}
                response.Headers.Add(HttpHeaderName.ETAG, ETag.Create(fhirResponse.Key.VersionId)?.ToString());
                response.Headers.Add(HttpHeaderName.LOCATION, location.OriginalString);
                    response.Headers.Add(HttpHeaderName.CONTENT_LOCATION, location.OriginalString);
                        response.Headers.Add(HttpHeaderName.LAST_MODIFIED, fhirResponse.Resource.Meta.LastUpdated.Value.ToString("R"));
                    if(fhirResponse.Resource is Binary)
                    {
                        response.Content.Headers.Add(HttpHeaderName.CONTENT_DISPOSITION, "attachment");
                    }
                context.HttpContext.Response.Headers.Add(HttpHeaderName.CONTENT_DISPOSITION, "attachment");
                    if (context.Request.Headers.ContainsKey(HttpHeaderName.ACCEPT)) context.Request.Headers.Remove(HttpHeaderName.ACCEPT);
                        context.Request.Headers.Add(HttpHeaderName.ACCEPT, new StringValues(ContentType.JSON_CONTENT_HEADER));
                        context.Request.Headers.Add(HttpHeaderName.ACCEPT, new StringValues(ContentType.XML_CONTENT_HEADER));
                    context.Request.Headers.Add(HttpHeaderName.X_CONTENT_TYPE, contentType);