Skip to content

HyperDX Uses a Public Default Express Session Secret #3089

Description

@28Hus

HyperDX Uses a Public Default Express Session Secret

Summary

HyperDX uses the public value hyperdx is cool 👋 when
EXPRESS_SESSION_SECRET is not configured:

const DEFAULT_EXPRESS_SESSION = 'hyperdx is cool 👋';

export const EXPRESS_SESSION_SECRET = (env.EXPRESS_SESSION_SECRET ||
  DEFAULT_EXPRESS_SESSION) as string;

Source: config.ts

The value is used as the signing secret for the express-session cookie:

const sess = {
  // ...
  secret: config.EXPRESS_SESSION_SECRET,
  store: new MongoStore({ mongoUrl: config.MONGO_URI }),
};

app.use(session(sess));

Source: api-app.ts

Anyone who knows the public source can generate valid signatures for arbitrary
connect.sid values. This weakens the integrity protection of the session
cookie.

Authentication flow

The Session Cookie carries a Session ID. HyperDX stores the Passport user
identifier in the corresponding server-side session, and Passport later loads
the user from MongoDB:

passport.serializeUser(function (user, done) {
  done(null, (user as any)._id);
});

passport.deserializeUser(function (id, done) {
  findUserById(id).then(user => {
    if (user == null) return done(null, false);
    done(null, user);
  });
});

Source: passport.ts

Protected routes rely on req.isAuthenticated():

if (req.isAuthenticated()) {
  return next();
}
res.sendStatus(401);

Source: auth.ts

Proof of concept

Run this only against a local HyperDX test instance. The following creates a
correctly signed cookie for an attacker-chosen session ID:

const signature = require('cookie-signature');

const sessionId = 'attacker-chosen-session-id';
const signed = `s:${sessionId}.${signature.sign(
  sessionId,
  'hyperdx is cool 👋',
)}`;

console.log(encodeURIComponent(signed));

Send the result to a protected API route:

curl -i \
  -H 'Cookie: connect.sid=<url-encoded-signed-cookie>' \
  http://127.0.0.1:8000/me

Expected result: 401 Unauthorized. The cookie signature is valid, but the
chosen session ID has no corresponding authenticated session in MongoDB.

As a positive control, log in to the local test instance, retain the returned
connect.sid cookie, and request /me. The request succeeds because Passport
can recover the user from the server-side session.

Impact

The default hyperdx is cool 👋 secret allows an attacker to sign arbitrary
session-cookie values without knowing the deployment secret.

The secret alone does not prove arbitrary user impersonation in the current
flow. A successful impersonation would additionally require a session-state
weakness, such as disclosure or fixation of a valid session ID, or the ability
to create or modify the referenced MongoDB session.

The issue is directly exploitable in deployments that omit
EXPRESS_SESSION_SECRET and also expose one of those session-state
conditions. Otherwise, the demonstrated impact is the use of a public default
for a production authentication secret.

Remediation

  • Remove hyperdx is cool 👋 as the fallback in authenticated deployments.
  • Require a deployment-specific high-entropy EXPRESS_SESSION_SECRET.
  • Fail closed at startup when the secret is missing or equals the public
    placeholder.
  • Rotate the secret and invalidate existing sessions after applying the fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingexternal

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions