Session hijacking has quietly become the top way attackers get into corporate accounts in 2026, and it works whether or not you have MFA turned on. A single infostealer infection now yields an average of 44 passwords but 1,861 cookies, according to password and passkey usage research published in mid-2026, and cookies are what attackers actually want. Underground markets tracked stolen session cookie volume climbing to roughly 8.6 billion in circulation this year, feeding subscription services that run automated Microsoft 365 and Google Workspace takeover campaigns for a monthly fee. This tutorial shows you, step by step, how to detect a hijacked session, cut off the attacker’s stolen cookie or token before it does damage, and close the gaps that let session theft skip past MFA and even passkeys in the first place.
By the end you will have working code for cookie flag auditing, a SIEM detection rule for session reuse, a token revocation script for Entra ID and Okta, and a small Python session-anomaly detector you can run against your own logs today. Primary keyword focus: session hijacking detection and defense, alongside cookie theft, token theft, and pass-the-cookie attacks against modern identity providers.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
Why Session Hijacking Beats MFA and Passkeys in 2026
Multi-factor authentication and passkeys protect the login event. They do nothing to protect what happens after the login event, and that gap is exactly what session hijacking exploits. Once a user authenticates, the server hands back a session cookie or an OAuth token that says, in effect, “this device already proved who it is, stop asking.” If an attacker steals that cookie or token and replays it from a different machine, most systems accept it without a second thought, because no new authentication challenge fires.
The OWASP Cookie Theft Mitigation Cheat Sheet puts it plainly: “However, if attacker can steal a valid session cookie instead, it is possible to hijack the user session for the duration of the session lifetime period.” That single sentence explains why a company can roll out FIDO2 passkeys everywhere and still get breached the same quarter. The passkey did its job. The session it created afterward was left unguarded, and a stealer log picked it up.
A field guide synthesizing Mandiant incident-response data and CrowdStrike reporting from earlier this year frames the shift bluntly: the typical modern intrusion does not crack a password and does not bypass MFA through brute force. It skips authentication entirely by stealing the session cookie that authentication already produced. That reframing matters for how you build defenses. Password strength and MFA enrollment rates are the wrong metrics to obsess over if session tokens are walking out the door in cleartext logs, unencrypted browser storage, or a 45-second infostealer run.
Prerequisites: Tools and Access You Need Before Starting
This tutorial assumes admin-level access to at least one identity provider and a willingness to run a few scripts against test accounts before touching production. Gather the following before Step 1.
- Chrome 152.0.7977.65 or later, or another Chromium browser on the same patch baseline (this version closes CVE-2026-79178 and CVE-2026-79108, both WebAuthn/session-adjacent authorization bypass bugs patched August 25, 2026)
- Admin access to Microsoft Entra ID (formerly Azure AD) with the AzureAD or Microsoft Graph PowerShell module, version 2.25 or later
- Admin access to an Okta tenant, or equivalent access to your primary SSO/IdP
- Python 3.11 or 3.12 with
requestsandpandasinstalled, for the session-anomaly detector project later in this guide - A SIEM or log pipeline that accepts custom detection rules (examples below use Sigma-style pseudocode and Microsoft Sentinel KQL, both portable to Splunk or Elastic with minor syntax changes)
- Burp Suite Community Edition or OWASP ZAP for inspecting cookies and headers during testing
- A disposable or staging application where you can safely test cookie replay without touching real user sessions
- Roughly 90 minutes, split across identity provider configuration, detection rule authoring, and testing
How Modern Infostealers and AiTM Kits Steal Sessions
You cannot defend against session hijacking without understanding how the theft actually happens on an endpoint. Infostealer malware in 2025 and 2026 has been retooled specifically to harvest session data, not just saved passwords. A May 2026 technical breakdown of the shift notes that current variants pull session cookies, browser autofill data, extension tokens, and cached credentials in one pass, and singles out session cookies as the most valuable item because they represent an already-authenticated session ready to replay.
Lumma Stealer is the clearest example of how resilient this ecosystem is. A large 2025 takedown operation seized roughly 2,300 domains tied to Lumma’s infrastructure, and a separate action shut down more than 1,000 LummaC2 domains along with over 90 Telegram channels and Steam profiles used to sell it. Despite that, Microsoft’s threat intelligence team disclosed a new Lumma delivery chain on March 5, 2026 that infects victims through Windows Terminal rather than the more heavily monitored Win+R run dialog, evidence that the malware’s operators simply rebuilt around the takedown rather than folding.
Two newer attack patterns push beyond simple cookie theft and are worth building specific detections for.
EvilTokens and OAuth Refresh Token Persistence
Sekoia’s Threat Detection and Research team reported a kit called EvilTokens active since mid-February 2026 that captures both session cookies and OAuth access and refresh tokens. That second part matters: a stolen refresh token survives a password reset and can mint fresh access tokens on demand, so an incident responder who only rotates the user’s password and kills the current session leaves the door open. Refresh tokens have to be explicitly revoked, a step covered in Step 9 below.
OAuth Device Code Phishing
A device-code phishing pattern documented in July 2026 abuses the OAuth 2.0 device authorization grant, the flow designed for TVs and smart devices that lack a keyboard. The attacker generates a legitimate device code, then social-engineers the victim into entering that code on Microsoft’s real sign-in page and completing genuine MFA. Because the authentication is real, the tokens get issued, but they land in the attacker’s polling script instead of the victim’s device. Passkeys do not stop this attack, because the victim’s successful passkey login is precisely what the attacker needs to harvest valid tokens. This is a post-login authorization abuse, not a credential phishing problem, and it needs its own monitoring rule (see Step 12).
Step 1: Map Your Session Attack Surface
Before writing a single detection rule, inventory every place your organization issues a session cookie or bearer token: the main web app, the SSO provider, any SaaS admin consoles, internal tools behind a reverse proxy, and mobile app API sessions. For each one, record the session lifetime, whether it is a sliding or fixed expiration, and whether refresh tokens are involved. Most teams find during this step that at least one internal tool issues sessions that never expire, which is the single easiest fix on this entire list.
Prioritize identity providers and admin consoles first, since a hijacked admin session in Entra ID or Okta gives an attacker far more reach than a hijacked session on a marketing site.
Step 2: Audit Cookie Security Flags in Chrome DevTools
Open your application in Chrome, then open DevTools with F12, go to the Application tab, and expand Cookies under Storage. For every session-related cookie, confirm three flags are set: HttpOnly (blocks JavaScript access, stopping most XSS-based theft), Secure (blocks transmission over plain HTTP), and SameSite=Strict or Lax (limits cross-site sending). A cookie missing any of these three is a soft target.
You can automate this check from the command line against a running app with curl, which is faster once you have more than a handful of endpoints to audit:
curl -s -D - -o /dev/null https://staging.example.com/login \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"test"}' \
| grep -i "set-cookie"
# Expected output should show all three flags on every session cookie:
# Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Strict; Path=/
If the response is missing HttpOnly or Secure, fix it at the framework level before moving on. A cookie without HttpOnly can be read by any injected script, and a cookie without Secure can be intercepted on a coffee shop network that strips TLS.
Step 3: Enforce Cookie Flags and Rotation at the Application Layer
If your app is built on Express.js, setting the flags correctly takes one configuration block. The example below also rotates the session ID on privilege changes, which limits the blast radius of a fixation-style attack where an attacker sets a known session ID before the victim logs in.
const session = require('express-session');
app.use(session({
secret: process.env.SESSION_SECRET,
name: 'session_id',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 30 * 60 * 1000 // 30-minute sliding expiration
}
}));
// Regenerate the session ID after login to defeat session fixation
app.post('/login', async (req, res) => {
const user = await authenticate(req.body);
if (!user) return res.sendStatus(401);
req.session.regenerate((err) => {
if (err) return res.sendStatus(500);
req.session.userId = user.id;
req.session.userAgent = req.headers['user-agent'];
req.session.ipPrefix = req.ip.split('.').slice(0, 3).join('.');
res.sendStatus(200);
});
});
Note the last two lines storing userAgent and a partial IP address in the session. That is the foundation for the environment-change detection covered next, and it directly follows OWASP’s recommended approach: “If you save this information when establishing a session and compare it in each request, you can detect if the user environment has changed.”
Step 4: Detect Session Reuse With Environment Fingerprint Checks
Add middleware that compares the stored fingerprint against the current request on every authenticated call. This will not catch a sophisticated attacker who spoofs a matching user agent, but it catches the overwhelming majority of stealer-log replay attempts, where the attacker’s machine has a different OS, browser version, or network entirely.
function detectSessionAnomaly(req, res, next) {
if (!req.session.userId) return next();
const currentUA = req.headers['user-agent'];
const currentIpPrefix = req.ip.split('.').slice(0, 3).join('.');
const uaMismatch = req.session.userAgent !== currentUA;
const ipMismatch = req.session.ipPrefix !== currentIpPrefix;
if (uaMismatch && ipMismatch) {
// Both signals changed at once: high-confidence hijack indicator
req.session.destroy(() => {});
logSecurityEvent('session_hijack_suspected', {
userId: req.session.userId,
previousUA: req.session.userAgent,
newUA: currentUA
});
return res.status(401).json({ error: 'session_invalidated', reason: 'reauthenticate' });
}
next();
}
This lines up with OWASP’s own guidance on the topic: “If a large change is detected when comparing this information each time a request is received, it is possible that the session has been hijacked,” and the recommended response is straightforward, per the same cheat sheet: “If there is a possibility that a session has been hijacked, the most reliable verification method is to re-authenticate.”
Step 5: Enable Continuous Access Evaluation in Microsoft Entra ID
If your organization uses Entra ID, Continuous Access Evaluation (CAE) shrinks the window an attacker has to use a stolen token. Instead of trusting an access token for its full lifetime (historically up to an hour), Microsoft’s own documentation on Continuous Access Evaluation confirms that CAE-enabled services revalidate near-real-time signals like IP address changes, account disablement, and password resets, and can cut off a token within minutes instead of waiting for natural expiration. Confirm CAE is active for your tenant’s supported services:
# Requires Microsoft Graph PowerShell module 2.25+
Connect-MgGraph -Scopes "Policy.Read.All"
Get-MgPolicyClaimMappingPolicy | Where-Object {
$_.DisplayName -like "*Continuous Access*"
}
# Check whether a specific app is enforcing CAE-aware token handling
Get-MgServicePrincipal -Filter "displayName eq 'YourAppName'" `
-Property "displayName,accountEnabled,servicePrincipalType"
CAE will not stop the initial cookie theft, but it drastically narrows how long a stolen Entra ID token stays useful once your security team spots the compromise, which is the entire point of pairing detection with fast revocation.
Step 6: Turn On Device-Bound Session Credentials in Chrome
Chrome’s device-bound session credentials feature ties a session’s refresh token to the specific device’s TPM or secure enclave, so a stolen cookie copied to another machine fails to refresh and dies with the short-lived access token. Google’s Chrome for Developers documentation describes this as binding session material to hardware rather than relying purely on a bearer token that works anywhere it is presented. For managed fleets, enable it through Chrome Enterprise policy:
{
"DeviceBoundSessionCredentialsEnabled": true,
"BrowserSignin": 2,
"PasswordManagerEnabled": false,
"SessionLengthLimit": 1800000
}
Deploy this via Group Policy on Windows or the Google Admin console for ChromeOS and managed Chrome. Setting PasswordManagerEnabled to false alongside it is deliberate: pushing users toward a dedicated corporate password manager instead of browser-stored credentials reduces what a single infostealer run can grab in one pass, since the browser’s local credential store is one of the first things stealer malware scrapes.
Step 7: Configure Okta Session Binding and the Admin Kill Switch
Okta documents session cookie theft directly in its own security advisories and recommends binding sessions to network and device signals where possible, alongside giving admins a fast way to terminate all active sessions for a compromised identity. In the Okta admin console, go to Security > Global Session Policy and confirm that session lifetime is capped (24 hours maximum is a reasonable ceiling for most workforces) and that reauthentication is required on new device or IP detection. For incident response, the relevant admin action is straightforward:
- Directory > People > select the affected user > Sessions > End all sessions
- Simultaneously reset the user’s password and force MFA re-enrollment if a hardware key was not used
- Review the System Log for
user.session.startevents immediately after the kill to confirm no new session was established from the same suspicious IP
Step 8: Write a SIEM Rule for Impossible Travel and Session Reuse
The single highest-value detection rule for session hijacking flags a session token being used from two geographically distant locations within a time window that makes physical travel impossible. Here is a Sentinel KQL version you can adapt to Splunk SPL or an Elastic detection rule with minor syntax changes:
SigninLogs
| where TimeGenerated > ago(1h)
| where ResultType == 0
| summarize Locations = make_set(pack("City", Location, "IP", IPAddress)),
LocationCount = dcount(Location),
IPs = make_set(IPAddress)
by UserPrincipalName, bin(TimeGenerated, 15m)
| where LocationCount > 1
| extend Severity = "High", AlertName = "Possible session token reuse: impossible travel"
| project TimeGenerated, UserPrincipalName, Locations, IPs, Severity, AlertName
Tune the 15-minute window against your own workforce’s travel patterns before enabling automated response. A remote team spanning multiple time zones using a corporate VPN with rotating exit nodes will trigger false positives at first; expect to spend the first week tightening the IP allowlist for known VPN and proxy ranges.
Step 9: Build an Automated Token Revocation Playbook
Detection without fast revocation just produces alert fatigue. This script, callable from your SIEM’s automation hook or SOAR platform, revokes all refresh tokens for a flagged Entra ID user, which is critical against the EvilTokens-style persistence described earlier, since killing only the current session cookie leaves a valid refresh token that can mint new access tokens.
import requests
import sys
def revoke_all_tokens(user_id, access_token):
"""Revoke all refresh tokens for a user via Microsoft Graph.
Requires User-Revoke-Session.All or equivalent admin-consented scope."""
url = f"https://graph.microsoft.com/v1.0/users/{user_id}/revokeSignInSessions"
headers = {"Authorization": f"Bearer {access_token}"}
resp = requests.post(url, headers=headers, timeout=10)
if resp.status_code == 200:
print(f"[OK] All sessions and refresh tokens revoked for {user_id}")
return True
else:
print(f"[FAIL] {resp.status_code}: {resp.text}", file=sys.stderr)
return False
if __name__ == "__main__":
flagged_user_id = sys.argv[1]
admin_token = sys.argv[2]
revoke_all_tokens(flagged_user_id, admin_token)
This mirrors the pattern documented in Microsoft’s own Revoke-AzureADUserAllRefreshToken reference, and it works whether you call it via PowerShell directly or through the Graph API endpoint shown above. Chain this script to fire automatically the moment the impossible-travel rule from Step 8 hits high confidence, with a human analyst reviewing within the hour. Waiting for a manual ticket queue defeats the purpose, since a stolen cookie is exploitable for the entire remaining session lifetime unless something actively kills it sooner.
Step 10: Test Your Defenses With a Controlled Cookie Replay
Verify the whole chain works before trusting it in production. On a staging environment, log in from one machine, copy the session cookie’s value using DevTools, then replay it from a second machine with a different user agent and IP:
# From "attacker" machine, replay the stolen cookie value
curl -s -o /dev/null -w "%{http_code}\n" \
https://staging.example.com/api/account \
-H "Cookie: session_id=" \
-H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) TestReplay/1.0"
# Expected: 401, and a session_hijack_suspected event in your logs within seconds
If the request returns 200 instead of 401, your environment fingerprint check from Step 4 is not wired into that route, or the middleware order in your app places authentication checks before the anomaly detector runs. Fix the middleware order and retest before moving to production.
Step 11: Monitor for OAuth Device Code Abuse
Since the device-code phishing pattern described earlier tricks a real user into completing genuine authentication, your detection has to focus on the token consumption pattern rather than the login itself. Watch for device code grants where the polling client’s IP or user agent never matches any of the organization’s known device fleet, and where the time between code generation and token issuance is unusually short (automated polling scripts complete this faster than a human manually entering a code on a second screen).
SigninLogs
| where AuthenticationRequirement == "deviceCode"
| where TimeGenerated > ago(24h)
| extend PollingIP = IPAddress
| join kind=inner (
DeviceLogonEvents | project DeviceId, KnownFleetIP = IPAddress
) on $left.PollingIP == $right.KnownFleetIP
| where isempty(DeviceId)
| project TimeGenerated, UserPrincipalName, PollingIP, AppDisplayName
Any hit here deserves a direct call to the user, not just an automated alert, since the login itself will show up as fully legitimate in every other log.
Step 12: Harden Endpoint-Level Cookie and Password Storage
The last structural fix reduces how much an infostealer can steal in the first place. A 2026 incident response playbook recommends disabling browser-native password saving via Group Policy or MDM and forcing use of a dedicated corporate password manager, on the logic that fewer credentials and cookies sitting in unencrypted or lightly-encrypted browser local storage means a lower-yield haul for any stealer that does land on an endpoint. Combine this with EDR rules tuned to catch known stealer families’ file access patterns, particularly reads against the Chrome/Edge/Firefox local state and cookie database files outside of the browser’s own process.
Session Hijacking on Mobile Apps and API Tokens
Everything above focuses on browser cookies because that is where the volume is, but mobile apps and pure API integrations have their own version of this problem, and it gets overlooked more often. A native mobile app typically stores a bearer token or refresh token in the device keychain or shared preferences rather than a cookie jar, and that storage is not automatically safer. On a rooted or jailbroken device, or one already infected with mobile-targeting malware, that token is just as extractable as a browser cookie is on a compromised laptop. The difference is visibility: most organizations have decent cookie-flag hygiene on their web app and close to zero monitoring on what their mobile app’s API backend accepts as proof of a valid session.
Two practical fixes close most of this gap. First, bind mobile API tokens to a device attestation check (Google Play Integrity API on Android, DeviceCheck or App Attest on iOS) so a token extracted from one device and replayed from an emulator or a different physical device fails attestation before it ever reaches your business logic. Second, apply the same impossible-travel and multi-subnet detection built in Step 8 to your API gateway logs, not just your web app’s sign-in logs; API traffic is frequently excluded from SIEM coverage simply because it was built by a different team on a different deployment timeline than the web frontend.
# Example API gateway log query, adapted from the Step 8 pattern,
# scoped to mobile/API traffic specifically
ApiGatewayLogs
| where TimeGenerated > ago(1h)
| where ClientType in ("mobile-ios", "mobile-android", "api-token")
| summarize IPs = make_set(ClientIP), Count = count()
by ApiKeyId, bin(TimeGenerated, 15m)
| where array_length(IPs) > 1
| project TimeGenerated, ApiKeyId, IPs, Count
Treat any hit from this query the same way you would treat a flagged browser session: it goes into the same revocation queue built in Step 9, just pointed at the API key or mobile refresh token instead of the web session cookie.
Complete Working Project: A Standalone Session Anomaly Detector
Put the pieces together into a script you can run today against exported sign-in logs (CSV from Entra ID, Okta System Log export, or your app’s own auth table), without waiting on SIEM integration work. This script flags any user account with sessions from more than one IP subnet inside a 15-minute window, exactly the pattern the KQL rule in Step 8 targets, but usable immediately against a flat file.
import pandas as pd
from datetime import timedelta
def find_session_anomalies(csv_path, window_minutes=15):
"""
Expects a CSV with columns: timestamp, user, ip_address, user_agent
Exported from Okta System Log, Entra ID sign-in logs, or app auth table.
"""
df = pd.read_csv(csv_path, parse_dates=["timestamp"])
df = df.sort_values(["user", "timestamp"])
df["ip_subnet"] = df["ip_address"].str.rsplit(".", n=1).str[0]
flagged = []
for user, group in df.groupby("user"):
group = group.reset_index(drop=True)
for i in range(len(group)):
window_start = group.loc[i, "timestamp"]
window_end = window_start + timedelta(minutes=window_minutes)
window_rows = group[
(group["timestamp"] >= window_start) &
(group["timestamp"] <= window_end)
]
distinct_subnets = window_rows["ip_subnet"].nunique()
distinct_agents = window_rows["user_agent"].nunique()
if distinct_subnets > 1 and distinct_agents > 1:
flagged.append({
"user": user,
"window_start": window_start,
"subnets": list(window_rows["ip_subnet"].unique()),
"user_agents": list(window_rows["user_agent"].unique())
})
return pd.DataFrame(flagged).drop_duplicates(subset=["user", "window_start"])
if __name__ == "__main__":
results = find_session_anomalies("signin_export.csv")
if results.empty:
print("No session anomalies detected in this export.")
else:
print(f"Flagged {len(results)} possible session hijack events:")
print(results.to_string(index=False))
Run it with python3 session_anomaly_detector.py after pointing the script at your exported log file. Treat every flagged row as a candidate for the revocation script from Step 9, and use the results to calibrate the time window before wiring the logic into a live SIEM rule.
Infostealer Families Targeting Sessions in 2025-2026
Knowing which malware families are active helps prioritize EDR signature coverage and threat-hunting queries. The table below reflects publicly reported status as of the most recent 2026 research and takedown reporting.
| Malware Family | Primary Target | 2025-2026 Status | Notable Detail |
|---|---|---|---|
| Lumma Stealer | Session cookies, passwords, crypto wallets | Core infrastructure disrupted, forks active | New Windows Terminal delivery chain reported March 2026 after ~2,300-domain takedown |
| RedLine Stealer | Browser credentials, cookies, FTP/VPN configs | Long-running, periodically disrupted | One of the most commonly sold logs on stealer marketplaces |
| Vidar | Session cookies, autofill, crypto wallets | Actively maintained, Telegram C2 variants | Frequently bundled with cracked software installers |
| Atomic Stealer (AMOS) | macOS Keychain, browser cookies | Active, macOS-specific | Distributed via fake software update prompts on macOS |
| Rhadamanthys | Cookies, credentials, 2FA seed extraction | Actively sold as malware-as-a-service | Targets browser extension-based 2FA/password tooling directly |
| EvilTokens kit | Session cookies and OAuth refresh tokens | Active since mid-February 2026 | Survives password resets by retaining refresh token validity |
Identity Provider Session Defenses Compared
If you are choosing where to invest configuration time first, this comparison of built-in session protection across the three most common identity platforms should help.
| Feature | Microsoft Entra ID | Okta | Chrome Enterprise |
|---|---|---|---|
| Near-real-time token revocation | Continuous Access Evaluation | End-all-sessions admin action | Device-bound session credentials |
| Refresh token control | Revoke-AzureADUserAllRefreshToken / Graph revokeSignInSessions | Session token revocation on password reset | N/A (browser-layer, not IdP) |
| Device binding | Compliant device conditional access | Device trust via Okta Verify | TPM/secure enclave binding of session material |
| Impossible travel detection | Identity Protection risk signals | Behavior detection (ThreatInsight) | Not applicable at browser layer |
| Admin manual kill switch | Yes, via Entra admin center or PowerShell | Yes, per-user session termination | Managed via Chrome Enterprise policy push |
Common Pitfalls When Implementing Session Hijacking Defenses
- Treating MFA as the finish line. Teams that roll out passkeys or hardware keys often stop there, assuming account takeover risk is solved. Session hijacking specifically targets what happens after that successful login, so passkey adoption has to be paired with session-layer controls, not treated as a replacement for them.
- Setting the environment-fingerprint check too strict. Comparing full user-agent strings and exact IP addresses causes constant false positives for users on mobile networks or corporate VPNs with rotating IPs. Compare IP subnets and browser family instead of exact matches, as shown in the Step 4 code.
- Forgetting refresh tokens during incident response. Revoking the active session cookie while leaving a valid OAuth refresh token in an attacker’s hands, especially against EvilTokens-style kits, means the attacker mints a fresh access token minutes later. Always revoke both together, as the Step 9 script does.
- Leaving internal tools out of the session policy. Security teams frequently lock down the main SSO and customer-facing app, then leave an internal admin panel or legacy tool issuing 30-day session cookies with no rotation. Attackers specifically look for these softer internal targets during lateral movement.
- Assuming device-code phishing shows up in login anomaly detection. Because the underlying authentication is completely legitimate, standard impossible-travel and risky-sign-in rules will not catch it. It requires the separate token-consumption monitoring covered in Step 11.
- Not testing the detection pipeline end-to-end. Many teams write a SIEM rule, confirm it parses correctly, and never actually replay a stolen cookie against staging to confirm the full chain (detection, alert, automated revocation) fires within an acceptable time window.
Troubleshooting Session Hijacking Detection Issues
- The Step 4 middleware never triggers. Check middleware order in your app; the anomaly detector must run after session load but the check inside it needs to run before any route handler that trusts
req.session.userId. - Continuous Access Evaluation shows no policy in Entra ID. CAE requires the target application to be CAE-aware; not every third-party SaaS app that federates through Entra ID supports it yet, so confirm the specific app’s documentation before assuming coverage.
- The KQL impossible-travel rule fires constantly for one user. That user is likely behind a corporate VPN or CDN-based proxy that rotates exit IPs across regions. Add the VPN provider’s known IP ranges to an allowlist before tuning further.
- The revocation script returns a 403 from Microsoft Graph. The service principal calling the script needs the
User-Revoke-Session.Allor equivalent application permission granted with admin consent, not just delegated permission. - Okta’s end-all-sessions action does not stop a mobile app session. Some native mobile SDKs cache tokens locally and do not immediately re-validate against Okta until the next API call; force a token refresh check by revoking the underlying OAuth client grant, not just the browser session.
- The Python anomaly detector flags almost every user. Your input CSV probably includes NAT-translated corporate egress IPs shared by hundreds of employees, collapsing everyone onto a few subnets and creating false correlations. Use per-device identifiers alongside IP where your logs provide them.
- Chrome device-bound session credentials policy does not apply. This feature requires a fully updated Chrome build on the enterprise channel; verify the exact build number against Chrome’s release notes, since policy support arrived incrementally across 2025 and 2026 releases.
- Cookie flags look correct in DevTools but the app still accepts a replayed cookie.
HttpOnly,Secure, andSameSitestop specific theft and transmission vectors, they do nothing once the raw cookie value has already been exfiltrated by an infostealer with local file system access. That scenario is exactly why Steps 4, 8, and 9 exist as a second layer.
Advanced Tips for Reducing Session Hijacking Risk
Once the baseline controls above are in place, a few additional moves meaningfully shrink your exposure. First, shorten session lifetimes for admin and privileged accounts specifically, separate from your general workforce policy; a 15-minute idle timeout on an Entra ID Global Administrator account costs almost nothing in convenience and removes most of the value from a stolen admin cookie. Second, require step-up authentication with a fresh hardware-key or device-bound passkey assertion for high-risk actions inside SaaS platforms, such as changing MFA settings, adding a new admin, or initiating a wire transfer, even when the existing session cookie is otherwise valid. Third, feed your EDR platform’s stealer-log detections directly into the Step 9 revocation script as an automated trigger, since incident response guidance now treats any stealer detection as a session-compromise event requiring device isolation within roughly four hours, not merely a malware cleanup ticket. Finally, review third-party OAuth app grants quarterly; an old, forgotten integration with a broad refresh-token scope is functionally identical to a permanently stolen session if that third party is ever compromised.
How This Fits Into a Broader Zero Trust Program
Session hijacking defense is not a standalone project, it is one layer of a wider identity security posture. If you have not already built a formal incident response process for identity compromise, that structure should exist before you need it during a live session hijacking event, not while one is unfolding. Pair the detection and revocation work in this guide with phishing detection training for end users, since AiTM phishing kits remain the most common way an attacker gets in front of a real login page in the first place, and with credential stuffing defenses at the API layer, since attackers frequently pivot from a stuffed credential to session harvesting once inside.
Budget for this work in phases rather than trying to ship all twelve steps in a single sprint. A realistic rollout puts cookie flag auditing and the environment-fingerprint middleware in week one, since both are entirely within your own application’s control and need no vendor coordination. Identity provider configuration (Continuous Access Evaluation, Okta session binding) follows in week two once you have confirmed which of your SaaS integrations actually support it. SIEM detection rules and the automated revocation playbook come last, in week three or four, because they depend on having clean, consistent log data from the first two phases to tune against. Skipping straight to automated revocation without first validating your detection rules against real traffic is how legitimate users end up locked out during a false-positive storm.
Frequently Asked Questions
Can session hijacking happen even with passkeys enabled?
Yes. Passkeys and hardware MFA protect the login event itself, but once a session cookie or OAuth token is issued after that login, it can still be stolen by infostealer malware on the endpoint and replayed elsewhere. Device-code phishing specifically abuses a legitimate passkey login to harvest the resulting tokens.
What is the difference between session hijacking and credential stuffing?
Credential stuffing uses leaked username and password pairs to attempt new logins, and MFA typically blocks it outright. Session hijacking skips the login entirely by stealing an already-authenticated session cookie or token, so no password and no MFA challenge is involved in the takeover itself.
How long does a stolen session cookie remain useful to an attacker?
It depends entirely on the session’s configured lifetime and whether the target system supports fast revocation like Continuous Access Evaluation. A cookie tied to a 24-hour session with no active monitoring stays valid for up to 24 hours; one protected by device-bound session credentials or immediate revocation on anomaly detection can be cut off within minutes of the theft being noticed.
Do I need to revoke refresh tokens separately from the session cookie?
Yes, and this is one of the most commonly missed steps in incident response. A refresh token can mint new access tokens independently of the browser session cookie, so kits like EvilTokens specifically target refresh tokens to survive password resets. Always revoke both, as shown in the Step 9 script.
Which browser cookie flags actually stop session theft?
HttpOnly blocks JavaScript-based theft via cross-site scripting, Secure blocks interception over unencrypted connections, and SameSite limits how the cookie gets sent on cross-site requests. None of the three stop an infostealer with direct file system access to the browser’s cookie database, which is why server-side anomaly detection and fast revocation matter just as much as correct cookie configuration.
Is session hijacking more common than credential-based attacks in 2026?
Multiple 2026 incident response and threat intelligence reports describe session cookie theft as the primary breach vector of the year, citing an average of roughly 44 passwords versus 1,861 cookies per single infostealer infection, and an estimated 8.6 billion stolen session cookies circulating in underground markets.
Can a SIEM rule alone stop session hijacking?
No. Detection rules like the impossible-travel query in Step 8 only identify suspicious activity; they need to be paired with an automated or fast manual revocation workflow, like the Step 9 script, to actually cut off the attacker’s access. Detection without response just produces alerts that arrive after the damage is already done.
Does device-bound session credentials in Chrome require an enterprise license?
The underlying feature is part of the open Chromium project, but enforcing it across a managed fleet via policy requires Chrome Enterprise or an equivalent management platform such as Google Admin console or Group Policy on Windows, since individual consumer installations do not have centralized policy enforcement.


