Back to Blog
high SEVERITY3 min read

PHP session_start() Missing Secure Cookie Flags in lasturl.php

The `session_start()` call in the last URL tracking component failed to set secure session cookie parameters, allowing session hijacking via man-in-the-middle attacks on HTTP connections or XSS exploitation. The fix configures `session_set_cookie_params()` with `httponly`, `secure`, and `samesite` attributes before starting the session.

O
By Orbis AppSec
•Published October 1, 2026•Reviewed October 1, 2026

Answer Summary

The affected code is first-party PHP code using `session_start()` without secure cookie configuration. An attacker on the same network can intercept session cookies on unencrypted HTTP connections, or steal them via XSS if JavaScript access is available. The fix adds `session_set_cookie_params()` with `httponly => true`, `secure => !empty($_SERVER['HTTPS'])`, and `samesite => 'Lax'` before `session_start()`. CWE-613 (Insufficient Session Expiration).

Vulnerability at a Glance

cweCWE-613
fixConfigure session_set_cookie_params() with httponly, secure, and samesite before session_start()
riskSession hijacking via MITM on HTTP or XSS cookie theft
languagePHP
root causesession_start() called without configuring secure cookie parameters
vulnerabilityMissing Secure Cookie Attributes on Session Cookies

Affected Versions

Affected not applicable (first-party code)
Fixed in not applicable (first-party code) — see fix commit
Ecosystem PHP
CVE / GHSA not assigned
CWE CWE-613 (Insufficient Session Expiration)

The Vulnerability Explained

PHP's session_start() function creates a session cookie using default configuration values that prioritize compatibility over security. In the vulnerable code, the session was started without explicitly setting the HttpOnly, Secure, or SameSite attributes:

session_start();
echo isset($_SESSION['lasturl']) ? urldecode($_SESSION['lasturl']) : null;

The lasturl session variable stores a redirect target, making this component particularly sensitive to session compromise—an attacker who steals this cookie could manipulate user navigation or impersonate authenticated sessions.

The attack path: When a user accesses the application over unencrypted HTTP (or if an attacker forces HTTP downgrades), the session cookie transmits in plaintext. Network attackers on the same Wi-Fi, ISP infrastructure, or compromised routers can intercept this cookie. Without HttpOnly, XSS payloads could also exfiltrate the cookie via document.cookie. The missing SameSite protection (defaulting to none in older PHP versions) additionally exposed the cookie to cross-site request forgery attacks.

The Fix

The remediation adds session_set_cookie_params() immediately before session_start():

session_set_cookie_params([
    'httponly' => true,
    'secure' => !empty($_SERVER['HTTPS']),
    'samesite' => 'Lax',
]);
session_start();
echo isset($_SESSION['lasturl']) ? urldecode($_SESSION['lasturl']) : null;

Why this specific configuration:

  • httponly => true: Prevents JavaScript access via document.cookie, blocking XSS-based cookie theft even if other vulnerabilities exist
  • secure => !empty($_SERVER['HTTPS']): Dynamically enables Secure flag when HTTPS is active, preventing MITM interception on encrypted connections while maintaining functionality in HTTP development environments
  • samesite => 'Lax': Restricts cookie transmission to same-site requests and top-level navigations, stopping CSRF attacks that rely on cross-site POST requests

The !empty($_SERVER['HTTPS']) pattern is particularly important for this codebase—it detects HTTPS presence without requiring hardcoded configuration, making the fix deployable across development, staging, and production without environment-specific changes.

Key Takeaways

  • Always configure session_set_cookie_params() before session_start() — PHP's defaults have historically left cookies exposed, and explicit configuration is the only reliable defense
  • Dynamic Secure flag detection with $_SERVER['HTTPS'] allows single-codebase deployment across HTTP and HTTPS environments while maximizing protection where available
  • The lasturl session storage pattern appears in 61 locations in this codebase; each requires identical cookie hardening to prevent session hijacking across all entry points
  • Output encoding with urldecode() does not mitigate cookie theft — transport-layer and cookie-flags security are independent concerns that must both be addressed

How Orbis AppSec Detected This

  • Source: The session_start() function invocation in PHP's session management API
  • Sink: The session cookie transmitted to the client browser without Secure, HttpOnly, or SameSite attributes
  • Missing control: No prior call to session_set_cookie_params() or ini_set() configuring session.cookie_httponly, session.cookie_secure, or session.cookie_samesite
  • CWE: CWE-613 (Insufficient Session Expiration) — though more precisely CWE-1004 (Sensitive Cookie Without 'HttpOnly' Flag) and CWE-614 (Sensitive Cookie in HTTPS Session Without 'Secure' Flag) describe the cookie-specific aspects
  • Fix: Add session_set_cookie_params() with explicit httponly, secure, and samesite configuration before session_start()

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

This vulnerability exemplifies how PHP's convenient session_start() API conceals dangerous defaults. The lasturl redirect tracking functionality—seemingly simple session storage—became a session hijacking vector because the cookie carrying that session data traveled unprotected. The fix demonstrates that secure session management in PHP requires explicit configuration: session_set_cookie_params() must precede every session_start(), with careful attention to environment-aware Secure flag deployment.

Prevention and further reading

Frequently Asked Questions

Does the fix change how `$_SESSION['lasturl']` is accessed or encoded?

No, the fix only configures cookie security parameters before `session_start()`. The `urldecode($_SESSION['lasturl'])` output encoding remains unchanged.

Why use `!empty($_SERVER['HTTPS'])` instead of hardcoding `true` for the Secure flag?

This allows the code to work in both HTTP development environments and HTTPS production deployments without configuration changes, while still enforcing Secure when HTTPS is available.

Does `session_set_cookie_params()` affect all 61 locations mentioned, or just this one?

The fix shown applies to this specific location. Each of the 61 `session_start()` calls throughout the codebase requires the same `session_set_cookie_params()` configuration to fully remediate CWE-613.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #81

Related Articles

critical

Node.js Auth Query SQL Injection via Group Code Interpolation

A sign-in authorization check built its SQL query by mapping an `authorizedGroups` array into quoted string literals and joining them directly into a template literal, creating a classic SQL injection point in a critical authentication path. The fix replaces every interpolated value — including the previously "typed" parameter — with `?` placeholders bound through a value-builder helper, closing off the injection vector entirely.

critical

Tung Tung Tracker Admin API: Missing Authentication in `/api/sync`

The Tung Tung Tracker administrative API endpoints (`/api/sync`, `/api/backfill`, `/api/show`, `/api/overlay/hide`) relied solely on localhost origin and a static `X-Tracker` header for protection, allowing any local process to execute privileged operations. The fix introduces proper session-based authentication and a random IPC secret for desktop-to-server communication.

critical

POST /api/generate Lacks Authentication, Allowing Unauthenticated

A resume generation endpoint in a Node.js backend accepted requests from any caller with network access, allowing attackers to consume OpenAI API quota without restriction. The vulnerability stemmed from missing authentication middleware on a cost-bearing endpoint. The fix adds mandatory API key validation via HTTP headers before processing any generation requests.

critical

chrome.runtime.onMessage: Missing Sender Validation in Extension

A critical authentication flaw in a Chrome extension's message handling allowed arbitrary extensions and malicious web pages to trigger sensitive operations including script injection and tab manipulation. The vulnerability existed because chrome.runtime.onMessage listeners processed requests without verifying sender identity or origin, trusting any message source by default.

critical

Google Generative AI Keys Exposed in Client-Side Fetch URLs

A client-side AI model discovery utility was embedding Google Generative AI API keys directly in fetch request URLs, making them visible to any user inspecting network traffic or browser DevTools. The fix moves the key from the URL query parameter to a secure HTTP header, eliminating exposure while maintaining API authentication.

high

js-yaml 5.2.1 DoS: Exponential Parsing in Flow Collections

A denial-of-service vulnerability in js-yaml 5.2.1 allows an attacker to crash the parser by supplying deeply nested flow collections that trigger exponential parsing behavior. The fix in version 5.2.2 improves the parser's handling of these structures, preventing the algorithmic complexity attack. This is critical for any service accepting user-controlled YAML input.