Skip to content

CWE-614: Sensitive Cookie Without 'Secure' Flag - C# / ASP.NET Core

Overview

The Secure attribute on a cookie instructs the browser to only transmit the cookie over encrypted HTTPS connections. Without it, the cookie is also sent over plaintext HTTP. If a user navigates to an HTTP version of a page (or is redirected to one by an attacker), the browser sends the session cookie in the clear, allowing a network-level attacker to steal it.

In ASP.NET Core, cookies are created without the Secure flag by default unless explicitly configured. This applies to all cookies: session cookies, authentication cookies created by ASP.NET Core Identity, and any cookies set via Response.Cookies.Append(). The fix requires setting the flag at both the individual cookie level and globally via CookiePolicyOptions.

Primary Defence: Set Secure = true on every CookieOptions and configure CookiePolicyOptions.Secure = CookieSecurePolicy.Always as a global default. Enable HTTPS redirection (UseHttpsRedirection()) and HSTS (UseHsts()) to ensure no session exists over HTTP.

Common Vulnerable Patterns

// VULNERABLE - cookie transmitted over HTTP as well as HTTPS
Response.Cookies.Append("auth_token", tokenValue, new CookieOptions
{
    HttpOnly = true,
    SameSite = SameSiteMode.Strict,
    // Secure is false by default - cookie will be sent over HTTP
});

Why this is vulnerable:

  • Without Secure = true, the browser sends the auth_token cookie on HTTP requests too. An attacker on the same network (corporate Wi-Fi, ISP, or a man-in-the-middle) can capture it and impersonate the victim's session.

Session Configuration Without Secure Policy

// VULNERABLE - session cookie not flagged as Secure
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(30);
    options.Cookie.HttpOnly = true;
    // options.Cookie.SecurePolicy is not set - defaults to SameAsRequest
    // (sends cookie over HTTP if the request came via HTTP)
});

Why this is vulnerable:

  • SameAsRequest means the cookie is only marked Secure if the request that created the session was HTTPS. During development or behind certain reverse proxies, this can result in session cookies being issued without the Secure flag.
// VULNERABLE - authentication cookie may be sent over HTTP
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.Cookie.HttpOnly = true;
        options.Cookie.SameSite = SameSiteMode.Strict;
        // SecurePolicy not set - authentication cookie transmitted over HTTP
    });

Why this is vulnerable:

  • Authentication cookies contain or reference session credentials. Sending them over HTTP exposes them to passive network interception (e.g., network sniffing at public Wi-Fi).

Secure Patterns

// Program.cs - enforce Secure flag globally on ALL cookies
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.Secure   = CookieSecurePolicy.Always; // Force Secure flag on every cookie
    options.HttpOnly = HttpOnlyPolicy.Always;     // Force HttpOnly on every cookie
    options.MinimumSameSitePolicy = SameSiteMode.Strict;
});

var app = builder.Build();

app.UseHttpsRedirection(); // Redirect HTTP -> HTTPS
app.UseHsts();             // Instruct browsers to always use HTTPS (after first visit)
app.UseCookiePolicy();     // Apply the policy above

Why this works:

  • CookieSecurePolicy.Always overrides the Secure flag on every cookie, including those set by third-party middleware that may not set it themselves. UseHsts() instructs browsers to refuse HTTP connections after the first HTTPS visit.
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // SECURE
        options.Cookie.HttpOnly     = true;
        options.Cookie.SameSite     = SameSiteMode.Strict;
        options.Cookie.Name         = "__Host-Auth"; // __Host- prefix forces Secure + Path=/
        options.SlidingExpiration   = true;
        options.ExpireTimeSpan      = TimeSpan.FromHours(8);
    });

Why this works:

  • CookieSecurePolicy.Always ensures the Secure attribute is always set. The __Host- cookie name prefix adds additional browser-enforced security: the browser will reject the cookie if it arrives without Secure, with a Domain attribute, or with a Path other than /.
builder.Services.AddSession(options =>
{
    options.IdleTimeout              = TimeSpan.FromMinutes(30);
    options.Cookie.SecurePolicy      = CookieSecurePolicy.Always; // SECURE
    options.Cookie.HttpOnly          = true;
    options.Cookie.SameSite          = SameSiteMode.Strict;
    options.Cookie.IsEssential       = true;
});
// SECURE: explicit options on a manually set cookie
Response.Cookies.Append("preference", userPreference, new CookieOptions
{
    Secure   = true,
    HttpOnly = true,
    SameSite = SameSiteMode.Strict,
    Expires  = DateTimeOffset.UtcNow.AddDays(30),
    Path     = "/",
});

Why this works:

  • Explicitly setting Secure = true prevents the flag from being omitted regardless of global policy. Using SameSite = Strict also prevents the cookie from being sent on cross-site requests, mitigating CSRF.

Remediation Steps

Locate the Finding

  • Source: Any Response.Cookies.Append() call, AddSession(), AddCookie(), AddAuthentication()
  • Sink: CookieOptions or CookieAuthenticationOptions without Secure = true or SecurePolicy = Always

Apply the Fix

  • PRIORITY 1: Add CookiePolicyOptions.Secure = CookieSecurePolicy.Always and app.UseCookiePolicy() in Program.cs
  • PRIORITY 2: Update individual CookieOptions instances to set Secure = true explicitly
  • PRIORITY 3: Enable UseHttpsRedirection() and UseHsts() to ensure HTTPS is enforced end-to-end

Verify the Fix

  • Use browser developer tools to inspect cookies; confirm Secure flag is present on all session/auth cookies
  • In staging, navigate to the HTTP version of the app and confirm session cookies are not present
  • Rescan with the security scanner to confirm the finding is resolved

Check for Similar Issues

Search for: CookieOptions, AddSession(, AddCookie(, Response.Cookies.Append( - check each for Secure/SecurePolicy

Testing

  • Normal input: sign in over HTTPS and confirm authentication, session, and preference cookies continue to work.
  • Boundary input: test staging and reverse-proxy deployments where X-Forwarded-Proto or HTTPS termination affects request scheme detection.
  • Malicious input: browse the HTTP origin directly and inspect requests; sensitive cookies must not be sent without HTTPS.

Additional Resources