Last reviewed: November 2, 2026 (Asia/Shanghai). Sources fetched November 1, 2026 UTC.

Direct answer

Prevent session fixation in coding-agent patches by issuing a fresh session ID when authentication changes the session’s authority, retiring the previous ID on the server, and copying only explicitly approved anonymous state into the new session. Prove the transition with two clients: one completes login; the other retains the original pre-login cookie. That original cookie must never gain the authenticated user’s access.

The OWASP Session Management Cheat Sheet requires session ID renewal after privilege changes, including login, and destruction of previous IDs. A secure transport and a signed cookie do not establish that renewal happened.

Consider an agent-written login handler that validates a password and then assigns req.session.userId = verifiedUser.id. The credentials may be checked correctly, yet an anonymous session known to another party can acquire the user’s authority if its identifier survives login. The review must follow the identifier and its server-side record through the entire transition.

Who this is for

Use this workflow when a coding agent changes login handlers, session middleware, authentication callbacks, MFA completion, privilege elevation, logout, or session-store adapters. It is especially useful when a refactor makes login faster by reusing an existing session or moving persistence after a redirect.

The running example uses an opaque cookie identifier and a server-side session store, as documented by Express’s express-session middleware. Cookie-contained sessions and bearer-token systems need their own renewal and revocation designs. Here, logout ends the current application session; global logout, identity-provider logout, and revocation of independent tokens are separate contracts.

The sequences and fixtures below are proposed review criteria. No application deployment or execution of this test matrix is claimed.

Key takeaways

  • A valid anonymous session ID can still be unsafe to retain after login.
  • Finish credential and transaction validation before attaching authenticated authority to a fresh session.
  • Treat state migration as an allowlist, including any field that influences identity, tenant selection, or navigation.
  • Persist the new session before reporting login success, and stop on regeneration or persistence errors.
  • Test old-cookie replay against every worker after login and logout.
  • Review overlapping requests: a stale write can undermine invalidation or overwrite the browser’s new cookie.
  • Cookie flags protect delivery and scope; server-side state determines whether a copied cookie still authorizes access.

Sources checked

Three primary references were fetched successfully on November 1, 2026 UTC:

  • OWASP: Session Management Cheat Sheet supports strict session-ID acceptance, renewal after privilege changes, invalidation, server-enforced expiry, and credential-safe lifecycle logging.
  • Express: session middleware documents server-side session storage, regenerate(), save(), destroy(), cookie options, and store-dependent races involving parallel requests. Its login example regenerates the session and saves before redirecting.
  • MDN: Set-Cookie header defines Secure, HttpOnly, SameSite, host-only scope, cookie prefixes, and browser expiration behavior.

These maintained technical references support an evergreen engineering task. Their retrieval date is not a product-release or vulnerability-disclosure date. Match the Express APIs and session-store behavior to the versions in the repository; the test design below is an engineering recommendation derived from these references.

Contract details to verify

Name the authority transition

Write down what each stage permits before reviewing calls to a helper named login:

StageExample authorityRequired transition
AnonymousLocale and an untrusted return-route choiceNo authenticated principal
Credentials verifiedIdentity established for this login attemptCreate fresh session before granting application access
MFA pendingOnly the operations needed to finish MFANo full-account access
MFA complete or privilege elevatedExplicitly verified higher authorityRenew identifier; previous ID cannot obtain the new authority
Logged out or expiredNo protected accessInvalidate server-side authority and clear the browser credential

MFA staging is part of this example policy, not an assertion that every application uses the same session model. Define which events change authority and how all consumers observe that change.

Trace the routes that bypass the main password handler: remember-me restoration, federated callbacks, account switching, impersonation, and administrative elevation can create the same boundary. Completing an identity-provider exchange does not automatically renew the application’s local session.

Accept only identifiers the application issued

OWASP distinguishes permissive session handling, which adopts caller-selected IDs, from strict handling, which accepts only application-generated IDs. Review custom ID generators, fallback parsers, query parameters, hidden fields, and legacy URL rewriting. A request field must not select the identifier of a newly authenticated session.

An unknown identifier should never be adopted as a session with that same value. Reject it or establish a fresh anonymous session according to the application contract. Restrict the accepted transport to the intended cookie mechanism instead of silently accepting a URL parameter when a cookie is absent.

Strict acceptance alone does not finish the review. A person can know a legitimate, application-issued anonymous cookie. Use that valid cookie in the fixation test; an invalid signature that middleware rejects before login does not exercise the dangerous transition.

Regenerate before granting authority

The Express reference says regenerate(callback) initializes a new SID and session instance when complete. Review code in this order:

  1. Validate credentials and the login transaction, including required MFA and request-integrity checks for the intended authority.
  2. Capture only anonymous fields approved for migration, validating their values and meaning.
  3. Invoke the maintained session-regeneration operation and wait for its completion.
  4. On error, terminate the login path. An error callback must return or otherwise prevent fallthrough into authenticated writes.
  5. Populate the new session from the verified principal and approved state.
  6. Save the new session and await persistence before sending the success response or redirect.

Do not copy the whole previous session object into the new one. A submitted userId, role, tenantId, MFA flag, or authentication timestamp must not become authority because it survived an anonymous workflow. Derive identity and permissions from trusted authentication and authorization results. Revalidate any retained tenant selection against that identity.

Locale may be safe to retain after validation. A return destination needs a separate trusted navigation rule. Recreate session-bound request tokens using the framework’s documented lifecycle. Keep login and logout under the application’s CSRF review workflow ; changing a session ID does not prove that the browser intended the login request.

Express documents explicit save() as useful before redirects. A redirect that races persistence can deliver the user to a page before the session exists in the store. Saving first addresses that ordering problem; it does not make authentication, regeneration, and multiple store operations one atomic transaction.

Retire authority across workers and overlapping requests

Verify the real store adapter’s deletion, write, expiry, and cache behavior. Express warns that its default MemoryStore is unsuitable for production and does not scale beyond one process. A test passing in one process cannot establish invalidation across a deployed worker pool.

The same reference warns that resave can cause parallel requests to overwrite session changes, depending on the store. Choose its setting using the adapter’s documented touch and expiry support. Setting resave: false reduces unnecessary writes; it is not a general guarantee against stale requests that actually modify session state.

Pause an old-session request after it loads state, complete login or logout in another request, then release the paused request. Check whether it can recreate a retired record, restore authenticated fields, or send a late cookie that replaces the browser’s new one. An anonymous replacement can still break login usability even when it grants no protected access.

Where stale writes can restore revoked authority, require an adapter or application mechanism that rejects those writes, such as a checked revocation generation or serialized transition. The required property is durable invalidation visible to every authorization path. A process-local lock or deleting one store key does not establish that property by itself. These are implementation requirements to verify, not guarantees supplied by regenerate().

For login, never provide an old-ID alias that returns the authenticated replacement or its credential. A compatibility window for periodic renewal must not allow a known pre-login identifier to cross the authentication boundary.

Review the actual response through the deployed HTTPS proxy. MDN defines Secure as restricting cookie delivery to secure requests, and HttpOnly as denying JavaScript access while still allowing the browser to send the cookie. Choose SameSite deliberately for the application’s navigation and federation requirements.

For a host-bound session cookie, omit Domain. A __Host- name additionally requires Secure, Path=/, and no Domain in supporting browsers; add HttpOnly separately. MDN warns that prefix assurances depend on browser support. Check for older cookies with the same name at different paths or domain scopes during migrations.

Keep server-side idle and absolute expiry distinct from browser cookie lifetime. MDN notes that browser session restoration can restore session cookies. OWASP requires server-enforced expiration and invalidation. Closing a window or removing a cookie cannot prove that another copy lost its authority.

Happy-path operator workflow

Freeze the agent revision, framework version, adapter version, and session policy. Use disposable accounts and the actual middleware, shared test store, and proxy configuration. Establish an anonymous browser session, retain its cookie privately, and complete a legitimate login with all required request proofs.

Confirm that the application issues a fresh identifier, stores only the verified principal and approved migrated fields, and allows the intended protected action. Inspect the stored transition and cookie attributes using protected test tooling. Frontend JavaScript cannot read Set-Cookie, as MDN explains; use browser automation’s cookie interface or a controlled HTTP harness rather than adding a credential-echo endpoint.

Then replay the original cookie from a separate client that has not received the new cookie. Assert that it cannot obtain protected data, execute a protected action, or retrieve the authenticated replacement. Repeat against another worker. A new identifier observed by the legitimate browser is only one of these assertions.

Prove the boundary with a session matrix

These are acceptance tests to implement in the target repository:

FixtureRequired observation under the example policy
Valid login from an existing anonymous sessionFresh identifier; verified principal; intended protected operation succeeds
Original anonymous cookie replayed after loginNo authenticated identity, protected data, effect, or replacement credential
Unknown cookie or session ID supplied through a URL/body fieldCaller-selected identifier is not adopted
Invalid credentials or incomplete MFANo full-access session or protected effect
Approved locale plus untrusted role and tenant fieldsOnly validated approved state migrates; authority comes from trusted results
Regeneration or new-session persistence failsNo login success and no usable newly authenticated session left behind
Old request finishes after loginNo authority transfer to old ID; late cookie behavior remains usable
Successful logout, then exact logged-out cookie replayNo protected access on any worker
Paused authenticated request writes after logoutIt cannot restore logged-out authority for subsequent requests
Idle or absolute expiry reachedServer rejects protected access even if the client retains the cookie
HTTPS proxy and supported browser combinationsExpected cookie accepted with the intended flags and host scope

Keep the replay cookie fixed in a separate cookie jar. Automatic cookie updates or copied post-login cookies can accidentally turn a negative test into another legitimate client. Assert identity, protected-handler calls, and durable effects, rather than relying on a status code alone.

For overlap cases, use controlled synchronization around the store read and write instead of sleeps. Set the policy for already authorized in-flight operations explicitly: logout cannot undo work that committed before it. The stale-write fixture checks that a late completion cannot resurrect authority for future requests. Inject a clock for expiry checks.

Error-path operator workflow

If regeneration fails, stop before attaching the principal. If persistence fails after an authenticated candidate was built, the failure path must prevent that candidate from becoming usable, including through automatic end-of-response saves. Verify cleanup and revocation with the actual store; merely returning an error page is insufficient. When invalidation cannot be confirmed, use a controlled unavailable response and withhold protected access until authoritative state can be checked.

On logout, invalidate the server-side session and expire the browser cookie at its actual name and scope. Do not report successful termination while the copied cookie remains valid. Keep password-recovery and all-device invalidation requirements aligned with the separate password-reset review .

Retain the revision, adapter version, synthetic fixture label, transition result, worker identity, and protected-effect counts. OWASP recommends lifecycle logging without raw session IDs. Keep cookies, passwords, and complete session records out of shared logs and agent transcripts. If correlation is necessary, use the reviewed non-reusable correlation scheme rather than exposing the credential.

Failure modes

A cookie signature is treated as evidence of freshness. A correctly issued anonymous cookie can be known to somebody else. Test that exact cookie across login.

Regeneration runs after authenticated state is saved. The known identifier may acquire authority before replacement. Grant authority only on the fresh session.

The entire session is copied. Anonymous workflow fields can carry stale or untrusted authority. Migrate a validated allowlist.

One deletion is treated as permanent revocation. A delayed writer or worker cache may restore old state. Exercise the shared store and overlapping requests.

Only the browser cookie is cleared. Another copy may remain usable. Replay it against a protected endpoint after logout.

FAQ

Does HTTPS prevent session fixation?

It protects transport, but it does not prove that the server renewed an identifier after login. OWASP explicitly requires renewal independently of whether HTTP or HTTPS is used.

No. Verify that the previous server-side identifier cannot authorize access or obtain the replacement. The old-cookie replay is the decisive test.

Does resave: false solve logout races?

It can avoid unnecessary writes, subject to the store’s requirements. A request that modifies state can still write after logout. Test that ordering and require durable revocation where needed.

Must every ordinary request create a new session ID?

No. This workflow requires renewal when authority changes. Periodic renewal is a separate policy with its own overlap and usability considerations; it does not replace idle or absolute expiry.

Reader next step

Choose one agent-written login change and retain a valid anonymous cookie before signing in. Prove legitimate access with the new session, then replay the untouched old cookie through another worker. Add the paused-write logout fixture before approving the patch. The evidence should show that new authority belongs only to the renewed session and cannot return through a retired identifier.