Authentication and Session Management
Authentication and Session Management at a glance
Overview
Authentication proves who a user is, session management keeps that identity across requests. If either is weak, an attacker can take over real accounts. Common mistakes include reading session data with user chosen keys, committing secrets to source, skipping cookie protections, and reusing sessions across privilege changes.
Good handling keeps tokens unpredictable and protected, ties the session to expected context, and keeps lifetimes short. Authentication should verify credentials with rate limits and clear failure paths.
Where it occurs
It shows up when handlers read from session using params, cookies, or headers as keys, when apps hardcode session secrets, or when cookie flags like HttpOnly and Secure are disabled. Weak defaults and copied snippets make this easy to miss.
Impact
An attacker can read or change another user's session state, impersonate users, and access admin functions. This leads to account takeover, leakage of personal data, fraudulent actions, and loss of trust. Because requests use a valid session, incident response and audits are harder.
Prevention
Never derive session ids or keys from user input. Load strong secrets from environment or a secret manager, never from source files. Set cookie flags Secure and HttpOnly, and SameSite=Lax or Strict where possible. Invalidate sessions on logout and privilege changes, rotate ids on login, and apply short idle and absolute expirations. Add rate limits to login, and use multi factor for sensitive actions.
Examples
Switch tabs to view language/framework variants.
Spring Boot, code decodes JWT without verifying signature
The server decodes a JWT and trusts claims without verifying its signature.
import com.auth0.jwt.JWT;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class JwtFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest r = (HttpServletRequest) req;
String auth = r.getHeader("Authorization");
if (auth != null && auth.startsWith("Bearer ")) {
String token = auth.substring(7);
// BUG: decode() does not verify signature
com.auth0.jwt.interfaces.DecodedJWT decoded = JWT.decode(token);
String role = decoded.getClaim("role").asString();
// trust the role claim directly
r.setAttribute("role", role);
}
chain.doFilter(req, res);
}
}- Line 11: JWT.decode(token) parses the token but does not verify its signature
- Line 13: Trusting claims from an unverified token allows forged tokens
Decoding a JWT without verification lets an attacker craft a token with arbitrary claims. If those claims control authorization or session state, the attacker can escalate privileges.
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
Algorithm algorithm = Algorithm.HMAC256(System.getenv("JWT_SECRET"));
JWTVerifier verifier = JWT.require(algorithm).build();
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest r = (HttpServletRequest) req;
String auth = r.getHeader("Authorization");
if (auth != null && auth.startsWith("Bearer ")) {
String token = auth.substring(7);
// verify signature - throws if invalid
DecodedJWT decoded = verifier.verify(token);
String role = decoded.getClaim("role").asString();
r.setAttribute("role", role);
}
chain.doFilter(req, res);
}- Line 6: Load secret from environment, not commit to source
- Line 12: Use verifier.verify(token) which checks signature and expiration
Verifying the token signature ensures the token originated from a trusted issuer and has not been tampered with. Also check expiry and audience.
Engineer Checklist
-
Do not use request values to choose a session key or id
-
Set cookie flags HttpOnly, Secure, and SameSite
-
Load strong secrets from env or a secret manager
-
Rotate session id on login and privilege change
-
Expire sessions on logout and short idle
-
Rate limit login and require MFA for sensitive actions
End-to-End Example
A small app exposes GET /profile that reads a value from session using a key from the query string. In production the cookie lacks the Secure flag due to a copied dev config. A user on shared Wi Fi leaks a valid session.
// Express example, similar pattern in other stacks
const express = require('express');
const session = require('express-session');
const app = express();
app.use(session({ secret: 'dev-secret', resave: false, saveUninitialized: false, cookie: { secure: false } }));
app.get('/profile', (req, res) => {
const key = req.query.key; // bug: user controls key
res.send(String(req.session[key]));
});// Express secure handler and cookie settings
const express = require('express');
const session = require('express-session');
const app = express();
app.set('trust proxy', 1);
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { secure: true, httpOnly: true, sameSite: 'lax' }
}));
app.get('/profile', (req, res) => {
const allowed = new Set(['theme']);
const key = req.query.key;
if (!allowed.has(key)) return res.status(400).send('unsupported');
return res.send(String(req.session[key]));
});Discovery
This vulnerability is discovered by analyzing session cookie attributes and testing for weak session management through cookie inspection, session token predictability analysis, timeout testing, and probing for session fixation or insecure transport.
-
1. Observe endpoint behavior
httpAction
Access the /profile endpoint with a benign query parameter to understand the response pattern
Request
GET https://app.example.com/profile?key=themeResponse
Status: 200Body:{ "note": "Response returns 'dark', indicating the endpoint reads from session using the key parameter" }Artifacts
http_response_body http_status -
2. Test with different keys
httpAction
Try various key values to confirm user-controlled session field access
Request
GET https://app.example.com/profile?key=last_actionResponse
Status: 200Body:{ "note": "Response returns '/dashboard/settings', confirming arbitrary session field read capability" }Artifacts
http_response_body log_line -
3. Identify sensitive session fields
analysisAction
Test common session field names (userId, email, role, plan_id, isAdmin) to discover what data is accessible
Request
ANALYSIS N/A - Analysis stepResponse
Status: 200Body:{ "note": "Successfully retrieved values for 'userId' (12345), 'email' (user@example.com), and 'plan_id' (premium_annual), revealing sensitive session data is exposed" }Artifacts
session_field_inventory -
4. Check cookie security flags
browserAction
Inspect cookie headers in browser developer tools and test HTTP vs HTTPS requests
Request
ANALYSIS N/A - Analysis stepResponse
Status: 200Body:{ "note": "Session cookie lacks Secure flag and is transmitted over HTTP, making it vulnerable to network interception" }Artifacts
cookie_headers network_capture
Exploit steps
An attacker exploits this by intercepting insecure session tokens, extracting sensitive session data through parameter manipulation, hijacking sessions through cookie theft or fixation, or maintaining persistent access by exploiting sessions that never expire.
-
1. Extract sensitive session data
Enumerate session fields
httpAction
Systematically request known session field names to extract user identity and account details
Request
GET https://app.example.com/profile?key=userIdResponse
Status: 200Body:{ "note": "Successfully retrieved userId: 12345, email: victim@company.com, plan_id: premium_annual, and role: admin revealing complete session state" }Artifacts
http_response_body extracted_session_data -
2. Capture session cookie via downgrade
Force HTTP connection
httpAction
Trick victim into clicking HTTP link or use MITM position on shared network to downgrade connection from HTTPS to HTTP
Request
GET http://app.example.com/profile?key=themeResponse
Status: 200Body:{ "note": "Session cookie transmitted in cleartext over HTTP, captured via network sniffing: connect.sid=s%3AjK8mN3pQ1rT5uV7wX9yZ2aB4cD6eF8gH" }Artifacts
network_capture session_cookie -
3. Hijack user session
Replay stolen cookie
httpAction
Use the captured session cookie to make authenticated requests as the victim user
Request
GET https://app.example.com/dashboardHeaders:Cookie: connect.sid=s%3AjK8mN3pQ1rT5uV7wX9yZ2aB4cD6eF8gHResponse
Status: 200Body:{ "note": "Successfully authenticated as victim, gained access to their dashboard, settings, and can perform privileged actions as admin user" }Artifacts
http_response_body session_proof -
4. Maintain persistence
Monitor session validity
analysisAction
Periodically test the stolen session to maintain access until it expires or user logs out
Request
ANALYSIS N/A - Analysis stepResponse
Status: 200Body:{ "note": "Session remains valid for 24 hours, allowing sustained unauthorized access to victim account" }Artifacts
session_lifetime_log
Specific Impact
Sensitive session values leak. This reveals private activity and internal state such as plan tiers or feature flags. The attacker does not need to authenticate as the victim, they only need a route that uses a param to select a session key.
Because the cookie lacked the Secure flag, any http request exposes the token. With that cookie the attacker replays the session and performs actions as the user until the session expires.
Fix
Cookie flags Secure and HttpOnly protect the token in transit and from script access. SameSite reduces cross site use.
The handler allows only a small safe subset of keys. Unknown keys get a 400.
The secret is loaded from environment, not source code.
Detect This Vulnerability in Your Code
Sourcery automatically identifies authentication and session management vulnerabilities and many other security issues in your codebase.
Scan Your Code for Free