Laravel Cookie Missing Secure Flag

Medium Risk Insecure Communication
laravelphpcookiessecure-flaghttpstransmission-security

What it is

The Laravel application sets cookies without the Secure flag, allowing them to be transmitted over unencrypted HTTP connections. This vulnerability exposes sensitive session data and authentication tokens to potential interception during transmission over insecure networks.

// Vulnerable: Cookies without Secure flag public function authenticateUser(Request $request) { $credentials = $request->only('email', 'password'); if (Auth::attempt($credentials)) { $token = $request->user()->createToken('auth')->plainTextToken; // Dangerous: Cookie can be sent over HTTP return response('Authentication successful')->cookie( 'auth_token', $token, 60 * 24, // 24 hours '/', null, false, // Secure flag disabled - DANGEROUS! true // httpOnly ); } } // Another vulnerable pattern public function storeSessionData(Request $request) { $sessionData = $request->session()->all(); // Dangerous: Missing secure flag Cookie::queue( 'app_session', encrypt(json_encode($sessionData)), 120, // 2 hours '/', null, false // Insecure transmission allowed ); } // config/session.php (vulnerable configuration) return [ 'secure' => false, // Dangerous in production 'http_only' => true, 'same_site' => 'lax', ];
// Secure: Proper Secure flag implementation public function authenticateUser(Request $request) { $credentials = $request->only('email', 'password'); if (Auth::attempt($credentials)) { $user = $request->user(); $token = $user->createToken('auth')->plainTextToken; // Secure: Enforce HTTPS transmission return response('Authentication successful')->cookie( 'auth_token', $token, 60 * 24, // 24 hours '/', config('session.domain'), true, // Secure flag - HTTPS only true, // httpOnly false, 'Strict' // sameSite ); } return response('Invalid credentials', 401); } // Environment-aware secure cookie setting public function storeSessionData(Request $request) { $sessionData = $request->session()->all(); // Secure: Environment-aware security $isProduction = app()->environment('production'); $isSecure = $isProduction || config('session.secure', false); Cookie::queue( 'app_session', encrypt(json_encode($sessionData)), 120, // 2 hours '/', config('session.domain'), $isSecure, // Secure in production true, // httpOnly false, 'Strict' // sameSite ); return response()->json(['status' => 'session_stored']); } // Service for secure cookie management class SecureCookieService { public function createSecureCookie($name, $value, $minutes = 60, $options = []) { $defaultOptions = [ 'path' => '/', 'domain' => config('session.domain'), 'secure' => $this->shouldUseSecureFlag(), 'httpOnly' => true, 'sameSite' => 'Strict' ]; $options = array_merge($defaultOptions, $options); return Cookie::make( $name, $value, $minutes, $options['path'], $options['domain'], $options['secure'], $options['httpOnly'], false, $options['sameSite'] ); } private function shouldUseSecureFlag() { // Always use secure flag in production if (app()->environment('production')) { return true; } // Use secure flag if HTTPS is available if (request()->isSecure()) { return true; } // Check configuration return config('session.secure', false); } public function validateCookieSecurity($cookieName) { $cookie = Cookie::get($cookieName); if (!$cookie) { return ['valid' => false, 'reason' => 'Cookie not found']; } $issues = []; // Check if served over HTTPS when Secure flag is set if (!request()->isSecure() && config('session.secure')) { $issues[] = 'Secure cookie served over HTTP'; } // Validate in production if (app()->environment('production') && !config('session.secure')) { $issues[] = 'Secure flag disabled in production'; } return [ 'valid' => empty($issues), 'issues' => $issues ]; } } // Middleware to enforce HTTPS and secure cookies class EnforceSecureCookiesMiddleware { public function handle($request, Closure $next) { // Redirect HTTP to HTTPS in production if (app()->environment('production') && !$request->isSecure()) { return redirect()->secure($request->getRequestUri(), 301); } $response = $next($request); // Validate all outgoing cookies foreach ($response->headers->getCookies() as $cookie) { $this->validateOutgoingCookie($cookie, $request); } return $response; } private function validateOutgoingCookie($cookie, $request) { $name = $cookie->getName(); // Log security issues if (!$cookie->isSecure() && $request->isSecure()) { Log::warning('Insecure cookie sent over HTTPS', ['cookie' => $name]); } if (app()->environment('production') && !$cookie->isSecure()) { Log::error('Cookie without Secure flag in production', ['cookie' => $name]); } } } // config/session.php (secure configuration) return [ 'driver' => env('SESSION_DRIVER', 'file'), 'lifetime' => env('SESSION_LIFETIME', 120), 'expire_on_close' => false, 'encrypt' => false, 'files' => storage_path('framework/sessions'), 'connection' => env('SESSION_CONNECTION', null), 'table' => 'sessions', 'store' => env('SESSION_STORE', null), 'lottery' => [2, 100], 'cookie' => env('SESSION_COOKIE', 'laravel_session'), 'path' => '/', 'domain' => env('SESSION_DOMAIN', null), 'secure' => env('SESSION_SECURE_COOKIE', app()->environment('production')), 'http_only' => true, 'same_site' => 'strict', ];

💡 Why This Fix Works

See fix suggestions for detailed explanation.

Why it happens

Laravel applications create cookies without explicitly setting the Secure flag, allowing cookies containing sensitive session data and authentication tokens to be transmitted over unencrypted HTTP connections. When developers use response()->cookie() or Cookie::queue() methods without specifying the secure parameter, or when they explicitly set it to false, cookies are transmitted regardless of protocol. Example: response()->cookie('token', $value, 60, '/', null, false, true) sets httpOnly but allows insecure transmission. This occurs because Laravel's default cookie behavior respects the secure parameter value rather than enforcing HTTPS-only transmission. Attackers on the same network can intercept HTTP traffic using packet sniffers like Wireshark or perform man-in-the-middle attacks to capture unencrypted cookie data. Without the Secure flag, session hijacking becomes trivial on public WiFi networks, coffee shops, or compromised routers where HTTP traffic is visible. The vulnerability is particularly dangerous for authentication cookies, remember-me tokens, and session identifiers that grant access to user accounts when stolen. Even if the initial login occurs over HTTPS, subsequent requests over HTTP expose cookies to interception if the Secure flag is not set.

Root causes

Missing Secure Flag in Cookie Configuration

Laravel applications create cookies without explicitly setting the Secure flag, allowing cookies containing sensitive session data and authentication tokens to be transmitted over unencrypted HTTP connections. When developers use response()->cookie() or Cookie::queue() methods without specifying the secure parameter, or when they explicitly set it to false, cookies are transmitted regardless of protocol. Example: response()->cookie('token', $value, 60, '/', null, false, true) sets httpOnly but allows insecure transmission. This occurs because Laravel's default cookie behavior respects the secure parameter value rather than enforcing HTTPS-only transmission. Attackers on the same network can intercept HTTP traffic using packet sniffers like Wireshark or perform man-in-the-middle attacks to capture unencrypted cookie data. Without the Secure flag, session hijacking becomes trivial on public WiFi networks, coffee shops, or compromised routers where HTTP traffic is visible. The vulnerability is particularly dangerous for authentication cookies, remember-me tokens, and session identifiers that grant access to user accounts when stolen. Even if the initial login occurs over HTTPS, subsequent requests over HTTP expose cookies to interception if the Secure flag is not set.

Development Settings Carried Over to Production

Development environment cookie configurations are mistakenly deployed to production systems without proper security hardening, creating transmission vulnerabilities that expose user sessions to network-based attacks. During local development, developers often disable the Secure flag to test applications over HTTP on localhost or internal networks where HTTPS certificates are not configured. Configuration files like config/session.php may contain 'secure' => false for development convenience, and these settings inadvertently remain unchanged when deploying to production environments. Environment variable misconfigurations compound the problem: SESSION_SECURE_COOKIE may be missing from .env.production files or incorrectly set to false, causing Laravel to serve cookies over both HTTP and HTTPS in production. Development-to-production parity issues arise when .env.example files include insecure defaults that developers copy without modification. Continuous integration/continuous deployment (CI/CD) pipelines may lack validation steps to verify secure cookie configuration before deployment. Infrastructure-as-code configurations might template insecure settings across multiple environments. Without environment-specific configuration management and deployment checklists, insecure development settings persist in production, exposing millions of user sessions to interception attacks on public networks.

Inadequate HTTPS Enforcement in Application

Laravel applications fail to enforce HTTPS across all routes and endpoints, allowing cookies with Secure flags to be bypassed when users access the application over HTTP, or cookies without Secure flags to be transmitted insecurely. Mixed-protocol environments where some pages serve over HTTPS while others use HTTP create security gaps where cookies remain accessible over insecure connections. Applications lacking HTTPS redirection middleware permit direct HTTP access to authenticated endpoints, exposing session cookies to network sniffing even when Secure flags are eventually set. Load balancers or reverse proxies that terminate SSL/TLS connections may incorrectly report the protocol to Laravel applications, causing request()->isSecure() to return false and conditional Secure flag logic to fail. Cloud environments like AWS ELB or Cloudflare proxies require proper configuration of X-Forwarded-Proto headers to detect HTTPS correctly, and misconfigured TrustProxies middleware results in Laravel treating secure connections as insecure. Content delivery networks (CDNs) serving mixed content or API endpoints accessible over HTTP create additional attack vectors. Without strict transport security headers (HSTS), browsers don't automatically upgrade HTTP requests to HTTPS, allowing attackers to downgrade connections and capture cookies. The absence of comprehensive HTTPS enforcement transforms Secure flag settings into unreliable protections that can be bypassed through protocol manipulation or direct HTTP access.

Missing or Incorrect Session Configuration

Laravel's session configuration in config/session.php lacks proper security settings for the 'secure' parameter, or environment variables controlling cookie security are misconfigured or absent entirely, resulting in insecure cookie transmission. Default Laravel installations often ship with 'secure' => false or conditional logic like 'secure' => env('SESSION_SECURE_COOKIE', false), which defaults to insecure behavior when SESSION_SECURE_COOKIE is not defined in environment files. Developers may be unaware that session security settings must be explicitly configured, assuming Laravel provides secure defaults for production environments. Complex configuration inheritance patterns where config/session.php references environment variables that are undefined in production .env files cause security settings to fall back to insecure defaults. Multi-environment deployments with inconsistent .env files across staging, production, and testing environments create security configuration drift. Docker containerization may bake insecure defaults into images when environment variables are not properly injected at runtime. Kubernetes ConfigMaps and Secrets containing session configuration might be copied from development templates without security hardening. Framework version migrations from older Laravel releases may not update session.php to include modern security defaults introduced in newer versions, leaving legacy insecure configurations in place that developers never revisit or audit.

Using HTTP in Production Environments

Production Laravel applications are deployed without proper HTTPS configuration, serving the entire application over unencrypted HTTP connections that expose all cookie data to network interception regardless of Secure flag settings. Infrastructure misconfigurations where web servers like Nginx or Apache lack SSL/TLS certificate installation leave applications accessible only via HTTP. Cost-cutting measures or technical knowledge gaps lead organizations to deploy without purchasing or configuring SSL certificates, particularly for internal applications or small projects. Let's Encrypt and other free certificate authorities are not utilized despite their availability, leaving applications unnecessarily vulnerable. Legacy deployment environments or shared hosting platforms may lack HTTPS support or require complex configuration that developers skip. Internal corporate networks where HTTPS is perceived as unnecessary because traffic is 'trusted' create false security assumptions that ignore insider threats and network compromise scenarios. Development operations teams may plan to add HTTPS later but launch HTTP-only MVPs (minimum viable products) that remain in production indefinitely. Cloud infrastructure misconfigured without SSL termination at load balancers or application gateways forces applications to accept HTTP traffic. Microservice architectures where internal service-to-service communication occurs over HTTP within a private network extend the attack surface when network segmentation is compromised. Without HTTPS, the Secure flag on cookies becomes meaningless as browsers never send those cookies, potentially breaking authentication flows while simultaneously allowing non-Secure cookies to be transmitted insecurely.

Fixes

1

Set Secure Flag to True for All Cookies in Production Environments

Explicitly configure the Secure flag for all cookies created in Laravel applications to enforce HTTPS-only transmission, preventing session hijacking and cookie interception over insecure networks. Use response()->cookie() with the secure parameter set to true: response()->cookie('token', $value, 60, '/', null, true, true, false, 'Strict') ensures cookies are only transmitted over encrypted connections. For queued cookies, use Cookie::queue('name', $value, 60, '/', null, true, true, false, 'Strict') with secure parameter in the sixth position. Create centralized cookie creation services that enforce security parameters consistently: a SecureCookieService class can encapsulate cookie creation logic with secure defaults that adapt based on environment. Implement environment-aware logic that automatically enables the Secure flag in production: config('app.env') === 'production' ? true : request()->isSecure() allows local development over HTTP while enforcing security in production. For session cookies, ensure config/session.php sets 'secure' => env('SESSION_SECURE_COOKIE', true) with a default of true, requiring developers to explicitly opt-out rather than opt-in to security. Set SESSION_SECURE_COOKIE=true in production .env files and verify this setting during deployment pipelines. Review all cookie creation points in the application including authentication flows, remember-me functionality, custom session management, and third-party package integrations to ensure consistent Secure flag usage.

2

Enforce HTTPS Across the Entire Application

Configure comprehensive HTTPS enforcement at multiple infrastructure and application layers to ensure all traffic is encrypted and Secure cookies function properly without protocol downgrade vulnerabilities. Install valid SSL/TLS certificates from trusted certificate authorities like Let's Encrypt, DigiCert, or commercial providers, ensuring certificates cover all domains and subdomains serving the application. Configure web servers (Nginx, Apache) to redirect HTTP traffic to HTTPS using 301 permanent redirects: in Nginx, add 'return 301 https://$host$request_uri;' to the HTTP server block. Laravel provides AppServiceProvider boot method for URL generation: URL::forceScheme('https') forces all generated URLs to use HTTPS regardless of incoming request protocol. Implement TrustProxies middleware correctly for cloud environments where load balancers terminate SSL: configure protected $proxies to include load balancer IPs and protected $headers to respect X-Forwarded-Proto headers, ensuring request()->isSecure() accurately detects HTTPS connections behind proxies. Add HTTP Strict Transport Security (HSTS) headers to force browsers to use HTTPS for all future requests: create middleware that sets 'Strict-Transport-Security: max-age=31536000; includeSubDomains; preload' on all responses. Enable HSTS preloading by submitting your domain to hstspreload.org to have major browsers automatically upgrade HTTP to HTTPS. Deploy Content Security Policy headers that include 'upgrade-insecure-requests' directive to instruct browsers to upgrade insecure resource requests to HTTPS automatically. Monitor certificate expiration and automate renewal processes using tools like certbot for Let's Encrypt certificates.

3

Configure Environment-Specific Cookie Security Settings

Implement robust environment-specific configuration management that automatically applies appropriate cookie security settings for development, staging, and production environments, preventing insecure development settings from reaching production. Structure config/session.php to use environment variables with secure production defaults: 'secure' => env('SESSION_SECURE_COOKIE', app()->environment('production')) ensures production environments default to secure cookies even if SESSION_SECURE_COOKIE is not explicitly set. Create separate .env files for each environment (.env.production, .env.staging, .env.local) with appropriate security settings documented and version-controlled through .env.example templates. In .env.production, explicitly set SESSION_SECURE_COOKIE=true, APP_ENV=production, APP_DEBUG=false, and LOG_LEVEL=warning to enforce production security posture. Use environment variable validation in AppServiceProvider to fail application startup if required security settings are missing in production: if (app()->environment('production') && !config('session.secure')) { throw new Exception('Secure cookies required in production'); }. Implement configuration testing in continuous integration pipelines that parse .env.production files and verify security-critical settings before deployment, preventing misconfigurations from reaching production. Use infrastructure-as-code tools like Terraform or AWS CloudFormation to template environment-specific configurations with security hardening built-in. For containerized deployments, inject environment variables at runtime through Kubernetes ConfigMaps and Secrets rather than baking them into Docker images, allowing environment-specific configuration without rebuilding images. Document environment-specific security requirements in deployment runbooks and enforce through automated deployment checks.

4

Use Laravel's Built-in Secure Cookie Configuration Options

Leverage Laravel's comprehensive cookie configuration system to manage secure cookie settings centrally and consistently across the application, reducing the risk of inconsistent security implementations. Configure config/session.php as the single source of truth for session cookie security, setting all security parameters: 'secure' => env('SESSION_SECURE_COOKIE', true), 'http_only' => true, 'same_site' => 'strict', 'domain' => env('SESSION_DOMAIN', null). Use Laravel's Cookie facade for application-wide cookie management with consistent security settings: Cookie::make() creates cookies respecting global configuration while allowing per-cookie overrides when necessary. Implement custom configuration values for application-specific cookies: create config/cookies.php with arrays defining security settings for different cookie types (authentication, preferences, tracking), then reference these configurations when creating cookies: $config = config('cookies.auth'); Cookie::make('auth_token', $value, $config['lifetime'], $config['path'], $config['domain'], $config['secure'], $config['httpOnly']). Create Blade directives or helper functions that encapsulate secure cookie creation: a secure_cookie() helper can apply default security settings while allowing developers to focus on business logic rather than security parameters. Use Laravel's Response class methods that automatically apply configured security settings: response()->cookie() inherits security settings from session configuration when parameters are omitted. Document Laravel's cookie configuration options in internal security guidelines, ensuring all developers understand how to create cookies securely and when to override defaults. Regularly review Laravel's release notes for cookie security enhancements and update applications to use new security features as they become available.

5

Implement HTTPS Redirection Middleware

Create and register Laravel middleware that enforces HTTPS redirection for all incoming HTTP requests, ensuring users and attackers cannot access the application over insecure connections that would expose cookies. Generate custom middleware using 'php artisan make:middleware ForceHttpsMiddleware' and implement handle method that checks if request is secure: if (!$request->isSecure() && app()->environment('production')) { return redirect()->secure($request->getRequestUri(), 301); }. Register middleware globally in app/Http/Kernel.php within the $middleware array to apply to all requests, or selectively in $middlewareGroups['web'] for web routes only if API routes have different requirements. Configure middleware to respect local development environments while enforcing HTTPS in production: environment checks ensure developers can test over HTTP locally without modifying code for deployment. Implement additional security checks within middleware: verify X-Forwarded-Proto header matches 'https' when behind load balancers or proxies, log insecure access attempts, and set HSTS headers on successful HTTPS responses. Handle edge cases such as health check endpoints that may need to accept HTTP for monitoring systems: use route-specific middleware exclusions or conditional logic. Add response security headers within the same middleware: set Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, and Content-Security-Policy headers to provide defense-in-depth. Test middleware thoroughly including redirect loops (when proxies incorrectly report protocol), performance impact of redirects, and compatibility with CDNs or reverse proxies. Monitor redirect behavior in production through application logs or application performance monitoring (APM) tools to identify misconfigurations that cause redirect loops or failed security enforcement.

6

Perform Regular Security Audits of Cookie Configurations

Establish recurring security audit processes that systematically review cookie configurations, validate security settings, and identify configuration drift or newly introduced vulnerabilities in cookie handling. Schedule quarterly security reviews where development and security teams examine all cookie creation points in the codebase, verify Secure flags are set appropriately, and confirm HTTPS enforcement remains effective. Use static analysis tools and custom linters to automatically detect insecure cookie patterns: create PHPStan or Psalm rules that flag Cookie::make() or response()->cookie() calls where the secure parameter is explicitly false or missing. Implement automated testing that validates cookie security attributes: create feature tests using Laravel's testing framework that make HTTP requests and assert response cookies include Secure, HttpOnly, and SameSite attributes with expected values: $response->assertCookie('session', null, false, true, 'strict'). Deploy runtime monitoring that logs cookie security attributes in production: middleware can inspect outgoing cookies and alert when Secure flags are missing on cookies sent over HTTPS connections. Conduct penetration testing that specifically targets cookie security: test cookie interception over HTTP, SSL stripping attacks, and protocol downgrade scenarios to validate defenses. Review third-party package cookie implementations: audit authentication packages, session management libraries, and analytics integrations to ensure they don't introduce insecure cookies that bypass application security controls. Maintain a cookie inventory documenting all cookies used by the application, their purposes, security attributes, and retention periods to facilitate compliance with regulations like GDPR and enable comprehensive security reviews. Update security policies and deployment checklists whenever cookie-related vulnerabilities are discovered or configuration changes are required.

Detect This Vulnerability in Your Code

Sourcery automatically identifies laravel cookie missing secure flag and many other security issues in your codebase.