Session Fixation in Feathersjs with Firestore
Session Fixation in Feathersjs with Firestore — how this specific combination creates or exposes the vulnerability
Session fixation occurs when an application assigns a user a session identifier before authentication and does not regenerate that identifier afterward. In a Feathersjs application using Firestore as the session store, the risk arises from how session identifiers are created, stored, and associated with user records.
Feathersjs does not enforce session regeneration on login by default. If the application relies on a session middleware (such as express-session) with a Firestore store, the session ID may be set on the client (for example, via a cookie) before the user authenticates. An attacker can force a known session ID onto a victim’s browser, often via a URL, an insecure link, or a malicious page. When the victim authenticates, the session record in Firestore is keyed to the attacker-chosen identifier, allowing the attacker to hijack the authenticated session.
With Firestore, the session document is typically stored with a document ID that matches the session ID. If the session ID is predictable or not rotated post-login, an attacker who knows the ID can read or modify the session document depending on Firestore security rules. For example, a session document might contain the user ID and a timestamp; if the attacker’s session ID maps to the same document structure, they can impersonate the user even after the user authenticates.
Additionally, if the Feathersjs service does not bind the session to additional context—such as IP address or user agent—an attacker who obtains a valid session ID can reuse it from different locations. Firestore security rules that are too permissive may allow read/write access to session documents based solely on document ID, which exacerbates the risk when the session ID is known or predictable.
To detect this pattern with middleBrick, you can run a scan against your Feathersjs API endpoint. The LLM/AI Security checks specifically probe for authentication and session handling weaknesses, including indicators of vulnerable session flows. The scanner maps findings to frameworks such as OWASP API Top 10 and provides remediation guidance without requiring credentials or setup.
Firestore-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on ensuring session identifiers are unpredictable, bound to the authenticated user, and rotated after login. Below are concrete code examples for a Feathersjs service using Firestore with express-session.
1. Configure express-session with Firestore store and secure options
Use a strong session store, set secure cookies, and enable cookie attributes to reduce exposure.
const session = require('express-session');
const FirestoreStore = require('connect-firestore')(session);
const sessionMiddleware = session({
store: new FirestoreStore({
projectId: 'your-project-id',
dataset: 'default',
collection: 'sessions',
expires: 14 * 24 * 60 * 60 * 1000 // 14 days
}),
name: '__Host-sid',
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 14 * 24 * 60 * 60 * 1000
}
});
app.use(sessionMiddleware);
2. Regenerate session on authentication
In your authentication hook, destroy the old session and create a new one to prevent fixation.
const { AuthenticationService } = require('@feathersjs/authentication');
const session = require('express-session');
class CustomAuthenticationService extends AuthenticationService {
async create(data, params) {
const result = await super.create(data, params);
const context = this.app.context;
if (context && context.params && context.params.req) {
const req = context.params.params.req || context.params.req;
if (req.session) {
req.session.regenerate((err) => {
if (err) throw err;
req.session.userId = result.user.id;
req.session.authenticated = true;
});
}
}
return result;
}
}
app.use('/authentication', new CustomAuthenticationService({
store: new FirestoreStore({/* options */}),
entity: 'user',
service: 'users'
}));
3. Bind sessions to user and enforce Firestore security rules
Structure session documents to include the user ID and enforce Firestore rules so users can only access their own session documents.
// Example Firestore security rule (pseudocode for rules clarity)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /sessions/{sessionId} {
allow read, write: if request.auth != null && request.auth.uid == request.resource.data.userId;
allow read: if request.auth != null && request.auth.uid == resource.data.userId;
}
}
}
In your Feathersjs service, ensure the session document includes the user ID:
// When creating/updating session data manually if needed
const sessionData = {
userId: user.id,
lastAccess: new Date().toISOString()
};
await app.service('sessions').create(sessionData);
4. Middleware to validate session-user binding on each request
Add a hook to verify that the session document matches the authenticated user, mitigating the impact of a leaked session ID.
app.hooks({
after: {
all: [async context => {
if (context.params && context.params.req && context.params.req.session) {
const session = context.params.req.session;
if (session.userId) {
const sessionDoc = await app.service('sessions').get(session.id);
if (!sessionDoc || sessionDoc.userId !== session.userId) {
throw new Error('Session mismatch');
}
}
}
return context;
}]
}
});
By combining secure cookie attributes, session regeneration, strict Firestore security rules, and server-side validation, you reduce the attack surface for session fixation in a Feathersjs + Firestore stack. middleBrick’s scans can validate these controls by checking authentication flows and session handling; the LLM/AI Security checks can further probe for weaknesses in authentication logic and prompt injection risks in related services.