HIGH session fixationexpressfirestore

Session Fixation in Express with Firestore

Session Fixation in Express with Firestore — how this specific combination creates or exposes the vulnerability

Session fixation occurs when an application accepts a session identifier provided by the client without ensuring it was established server-side after authentication. In Express, this commonly happens when session cookies (such as connect.sid) are not regenerated on login. When Express is combined with Firestore as a session store, the risk persists if session documents in Firestore are created or reused based on client-supplied IDs without server-side validation and rotation.

With Firestore, a typical vulnerable pattern is to store session data keyed by an identifier taken directly from a cookie set by the client. For example, if the client sends sessionId=12345 and the server writes a new Firestore document under that ID without issuing a new server-generated ID, an attacker can fix the session ID before tricking a victim into authenticating. After authentication, the attacker uses the known ID to hijack the session. Even if Firestore enforces security rules, the vulnerability is at the application layer: the server must treat session identifiers as secrets and never trust the client to choose them.

Express middleware like express-session can be configured with a custom store to use Firestore. If the store implementation does not enforce session regeneration on authentication and does not use cryptographically random document IDs, fixation persists. Firestore’s document naming flexibility means developers must deliberately generate server-side IDs (for example using a UUID library) and avoid merging or overwriting session documents based on untrusted input. Without explicit regeneration and strict ID assignment, the session management in Express-Firestore integrations mirrors classic web session fixation regardless of the database backend.

Additionally, because Firestore is a cloud-hosted NoSQL store, developers might assume built-in security replaces secure session handling. This is incorrect: security rules protect document access, but they do not prevent an attacker from using a predictable or client-supplied session ID. The application must still rotate session identifiers after login and ensure new Firestore session documents are created with server-generated IDs, not client-controlled paths.

To detect this pattern, scanners review session management flows and check whether session identifiers are regenerated after authentication and whether Firestore writes use server-generated keys. Findings typically highlight missing session rotation and overly permissive document creation logic that accepts client-supplied IDs.

Firestore-Specific Remediation in Express — concrete code fixes

Remediation focuses on ensuring every authenticated session uses a server-generated identifier and that session documents in Firestore are created under paths controlled exclusively by the server. Below is a secure Express setup using express-session and a custom Firestore store that generates session IDs server-side and writes to a dedicated collection.

const express = require('express');
const session = require('express-session');
const { Firestore } = require('@google-cloud/firestore');

const firestore = new Firestore();
const sessionsCollection = firestore.collection('sessions');

const app = express();

app.use(session({
  secret: process.env.SESSION_SECRET,
  name: 'sessionId', // avoid default to reduce fingerprinting
  resave: false,
  saveUninitialized: false, // do not create session until something stored
  store: {
    async get(sessionId, callback) {
      const doc = await sessionsCollection.doc(sessionId).get();
      callback(null, doc.exists ? doc.data() : null);
    },
    async set(session, callback) {
      // session.id is assigned by express-session (server-generated)
      await sessionsCollection.doc(session.id).set({
        data: session,
        updatedAt: firestore.FieldValue.serverTimestamp()
      });
      callback(null);
    },
    async destroy(sessionId, callback) {
      await sessionsCollection.doc(sessionId).delete();
      callback(null);
    },
    async touch(sessionId, session, callback) {
      await sessionsCollection.doc(sessionId).update({
        updatedAt: firestore.FieldValue.serverTimestamp()
      });
      callback(null);
    }
  },
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    maxAge: 24 * 60 * 60 * 1000
  }
}));

app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  // validate credentials against Firestore, e.g., users collection
  const userDoc = await sessionsCollection.doc(username).get();
  if (!userDoc.exists) return res.status(401).send('Invalid credentials');
  // express-session will automatically regenerate session if configured:
  req.session.regenerate((err) => {
    if (err) return res.status(500).send('Session error');
    req.session.user = { uid: userDoc.id, role: userDoc.data().role };
    return res.redirect('/dashboard');
  });
});

app.listen(3000);

Key points in this setup:

  • saveUninitialized: false prevents creation of session documents for unauthenticated visitors, reducing noise in Firestore and limiting exposure.
  • req.session.regenerate is called during login to issue a new server-side session ID, breaking any fixation that might have existed before authentication.
  • The Firestore store uses session.id (assigned by express-session) as the document ID, ensuring the server controls the identifier rather than accepting one from the client.
  • Secure cookie attributes (HttpOnly, Secure in production, SameSite) are set to mitigate transport-layer risks.

For production, consider additional hardening such as short session lifetimes, rotating secrets, and monitoring anomalous session creation patterns in Firestore. The goal is to ensure session identifiers are unpredictable, server-generated, and never reused across authentication boundaries.

Frequently Asked Questions

Can an attacker exploit session fixation if Firestore security rules restrict writes?
Yes. Security rules control who can read or write a document, but if the server accepts a client-supplied session ID and creates a document under that ID, an attacker can set the ID before login and later read the authenticated session data if rules permit. The fix is to always generate session IDs server-side and avoid using client-controlled IDs regardless of rules.
Does enabling Firestore offline persistence on the client affect session fixation risk?
Offline persistence in Firestore clients caches data locally and does not change server-side session management. The fixation risk is determined by how the server issues and manages session identifiers; client-side caching does not mitigate missing server-side regeneration.