Conversation
Vidoc Security ReportDetected 3 security issues.
Details{
"scanId": "019b12b2-cb22-73bf-b27e-11e9c9f5e383",
"codebaseId": "019ac6c3-c4db-70b0-aed6-bb82698030de",
"installationId": 84590600,
"internalPullRequestId": "019b12a8-28e4-7262-9869-76e5353b072f"
}
|
| app.use(express.urlencoded()); | ||
| app.use( | ||
| session({ | ||
| resave: false, // don't save session if unmodified | ||
| saveUninitialized: false, // don't create session until something stored | ||
| secret: "shhhh, very secret", |
There was a problem hiding this comment.
Severity: Medium
The session secret is hard-coded to a weak, guessable value. An attacker who knows or can guess this secret can forge or tamper with session data, potentially leading to authentication bypass and session hijacking.
Details
The Express application configures `express-session` with a single, hard-coded secret value (“shhhh, very secret”) and no environment-based override. This secret is used at runtime to sign session cookies. Knowledge of the secret enables forging validly signed session cookies, facilitating session fixation and hijacking when combined with obtaining or influencing a victim’s session ID. No alternative configuration, rotation, or production-only override is present; the same hard-coded secret governs verification.Why it's exploitable:
express-sessionis used withsecret: "shhhh, very secret"and no override logic.- The file directly starts the server, applying this configuration at runtime.
- Knowing the secret allows generating signed
connect.sidcookies, enabling session fixation or hijacking if an attacker can set or learn a session ID.
Why it's not exploitable:
- Not applicable; there is no evidence of environment-based secret management, rotation, or alternate production configuration.
Attack vector: network - An attacker can interact with the REST API over the network and supply forged cookies once the secret is known.
CVSS v3.1 vector: AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N - Exploitation generally requires either user interaction (session fixation) or knowledge of an existing session ID; impacts include confidentiality and integrity via account takeover.
Evidence:
- auth/index.js:9 — Session library import
9 | var session = require("express-session");- auth/index.js:21-27 — Session middleware with hard-coded secret
21 | app.use(
22 | session({
23 | resave: false, // don't save session if unmodified
24 | saveUninitialized: false, // don't create session until something stored
25 | secret: "shhhh, very secret",
26 | })
27 | );- auth/index.js:133-137 — Server bootstrap applying this configuration
133 | /* istanbul ignore next */
134 | if (!module.parent) {
135 | app.listen(3000);
136 | console.log("Express started on port 3000");
137 | }Debug
{
"id": "019b12b3-8015-74b8-8860-49dd0f1a65a6",
"codebaseId": "019ac6c3-c4db-70b0-aed6-bb82698030de",
"path": "auth/index.js",
"rangeStart": 21,
"rangeEnd": 26,
"line": 25,
"signature": "019b12b3-47f1-74a9-abc0-4b11f4ac2577"
}
|
|
||
| hash({ password: "foobar" }, function (err, pass, salt, hash) { | ||
| if (err) throw err; | ||
| // store the salt & hash in the "db" | ||
| users.tj.salt = salt; | ||
| users.tj.hash = hash; |
There was a problem hiding this comment.
Severity: Medium
A user credential is embedded directly in code by hashing a hard-coded password. This creates a default/backdoor account that attackers can exploit if the application is deployed with this code.
Details
A default credential is created by hashing the hard-coded password "foobar" and assigning the resulting salt and hash to the user `tj`. The authentication flow uses these values to validate logins. The server starts on port 3000 when the module is run directly, exposing a `/login` route that explicitly instructs use of "tj"/"foobar". There is no environment gating, first-run password change, or disabling mechanism, making this a network-exploitable default account wherever this app is deployed.Why it's exploitable:
- The password "foobar" is hard-coded and hashed at startup, populating
users.tj.saltandusers.tj.hash. - The
/loginroute validates credentials using the stored salt/hash and advertises "tj"/"foobar". - No environment checks or protections prevent this from running in production.
- The app listens on port 3000 when executed, exposing a network-accessible login.
Why it's not exploitable:
- None observed; no guards or rotation requirements are implemented.
Attack vector: network - The Express server starts and exposes /login over the network when run.
CVSS v3.1 vector: AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N - Network-accessible default credentials; post-auth access appears limited to a restricted page, reducing impact.
Evidence:
- auth/index.js:44-56 — users object and hard-coded password hashing
44 | var users = {
45 | tj: { name: "tj" },
46 | };
...
51 | hash({ password: "foobar" }, function (err, pass, salt, hash) {
52 | if (err) throw err;
53 | // store the salt & hash in the "db"
54 | users.tj.salt = salt;
55 | users.tj.hash = hash;
56 | });- auth/index.js:60-73 — authenticate() verifies against stored salt/hash
60 | function authenticate(name, pass, fn) {
62 | var user = users[name];
64 | if (!user) return fn(null, null);
68 | hash({ password: pass, salt: user.salt }, function (err, pass, salt, hash) {
70 | if (hash === user.hash) return fn(null, user);
71 | fn(null, null);
72 | });
73 | }- auth/index.js:104-131 — /login uses authenticate and advertises default creds
104 | app.post("/login", function (req, res, next) {
106 | authenticate(req.body.username, req.body.password, function (err, user) {
127 | ' (use "tj" and "foobar")';
128 | res.redirect("/login");
130 | });
131 | });- auth/index.js:133-137 — server starts when run directly
134 | if (!module.parent) {
135 | app.listen(3000);
136 | console.log("Express started on port 3000");
137 | }Debug
{
"id": "019b12b3-8018-73f9-a755-473081a6c4f4",
"codebaseId": "019ac6c3-c4db-70b0-aed6-bb82698030de",
"path": "auth/index.js",
"rangeStart": 51,
"rangeEnd": 56,
"line": 51,
"signature": "019b12b3-47f1-74a9-abc0-536eee2e061c"
}
|
|
||
| function authenticate(name, pass, fn) { | ||
| if (!module.parent) console.log("authenticating %s:%s", name, pass); |
There was a problem hiding this comment.
Severity: Medium
The code logs both the username and the plaintext password during authentication. Logging credentials can leak sensitive data to log files, monitoring systems, or third-party services, leading to account compromise.
Details
The authentication routine logs plaintext credentials when the module is executed directly, causing username and password to be written to stdout on every login attempt. The same file also starts the server when run without a parent module, making the logging active during real authentication traffic. While the logging is gated by `module.parent`, this application is designed to run standalone, so the guard evaluates true in that mode and credentials are exposed to logs that are typically collected by process managers or centralized logging systems.Why it's exploitable:
- The POST /login handler invokes
authenticate()withreq.body.usernameandreq.body.password. - Inside
authenticate(), aconsole.logprints both the username and plaintext password when the module has no parent (i.e., executed directly), which is the same condition under which the server is started.
Why it's not exploitable:
- If this module is only ever required by a parent module (module has a parent), the logging statement does not execute.
Attack vector: local - sensitive data exposure requires access to application logs/stdout, though any remote login request triggers the logging.
CVSS v3.1 vector: AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N - Reading the exposed credentials requires local or privileged access to logs; impact is high for confidentiality only. Base score: 1.4.
Evidence:
- auth/index.js:L60-L66 — authenticate
60 | function authenticate(name, pass, fn) {
61 | if (!module.parent) console.log("authenticating %s:%s", name, pass);
62 | var user = users[name];
63 | // query the db for the given username
64 | if (!user) return fn(null, null);
65 | // apply the same algorithm to the POSTed password, applying- auth/index.js:L104-L108 — /login route
104 | app.post("/login", function (req, res, next) {
105 | if (!req.body) return res.sendStatus(400);
106 | authenticate(req.body.username, req.body.password, function (err, user) {
107 | if (err) return next(err);
108 | if (user) {- auth/index.js:L133-L137 — server startup
133 | /* istanbul ignore next */
134 | if (!module.parent) {
135 | app.listen(3000);
136 | console.log("Express started on port 3000");
137 | }Debug
{
"id": "019b12b3-801b-755a-abbe-4ea57ae7e7a5",
"codebaseId": "019ac6c3-c4db-70b0-aed6-bb82698030de",
"path": "auth/index.js",
"rangeStart": 60,
"rangeEnd": 62,
"line": 61,
"signature": "019b12b3-47f1-74a9-abc0-586489c98e82"
}
No description provided.