Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions backend/config/passportConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ passport.use(
{ usernameField: "email" },
async (email, password, done) => {
try {
const user = await User.findOne( {email} ).select("+password");;
const user = await User.findOne({ email }).select("+password");
if (!user) {
return done(null, false, { message: 'Email is invalid '});
return done(null, false, { message: 'Email is invalid ' });
}

const isMatch = await user.comparePassword(password);
Expand All @@ -18,7 +18,7 @@ passport.use(
}

return done(null, {
id : user._id.toString(),
id: user._id.toString(),
username: user.username,
email: user.email
});
Expand All @@ -38,10 +38,14 @@ passport.serializeUser((user, done) => {
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findById(id);

// πŸ›‘οΈ Safety check: If the user record no longer exists in MongoDB, exit safely
// This prevents the application from throwing an unhandled TypeError downstream
if (!user) {
return done(null, false);
return done(null, false); // Gracefully invalidates the cookie and ends the request loop
}
done(null,user);

done(null, user);
} catch (err) {
done(err, null);
}
Expand Down
6 changes: 6 additions & 0 deletions backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@ app.use(cors({

// Middleware
app.use(bodyParser.json());

app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 24 * 60 * 60 * 1000,
secure: process.env.NODE_ENV === "production",
sameSite: process.env.NODE_ENV === "production" ? "none" : "lax"
}
Comment on lines +36 to +40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚑ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if CSRF middleware is used in the codebase
echo "=== Searching for CSRF middleware usage ==="
rg -n -i 'csurf|csrf' --type=js

echo ""
echo "=== Checking route handlers for Content-Type validation ==="
rg -n -C3 'app\.(post|put|patch|delete)' --type=js

echo ""
echo "=== Looking at auth routes for potential CSRF concerns ==="
fd -t f 'auth' --extension js --exec cat {}

Repository: GitMetricsLab/github_tracker

Length of output: 2971


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== backend/server.js (lines around 1-120) ==="
nl -ba backend/server.js | sed -n '1,140p'

echo
echo "=== Full search for csurf/csrf usage across repo ==="
rg -n -i 'csurf|csrf' --hidden --glob '!*node_modules/*'

echo
echo "=== Search for CSRF token patterns / middleware ==="
rg -n -i 'csrftoken|csrfToken|x-csrf|xsrf' --hidden --glob '!*node_modules/*'

echo
echo "=== Search for JSON-only / content-type validation on mutation routes ==="
rg -n -i 'content-type|application\/json|req\.is\(.+json' --hidden --glob '!*node_modules/*' --type=js

Repository: GitMetricsLab/github_tracker

Length of output: 180


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== backend/server.js: session/cookie config area ==="
cat -n backend/server.js | sed -n '1,140p'

echo
echo "=== rg: express-session usage ==="
rg -n "express-session" backend/server.js

echo
echo "=== rg: cookie/sameSite/secure/maxAge in backend/server.js ==="
rg -n "cookie|sameSite|secure|maxAge" backend/server.js

echo
echo "=== repo-wide rg: CSRF middleware usage (csurf/csrf) ==="
rg -n -i 'csurf|csrf' --hidden --glob '!*node_modules/*'

echo
echo "=== repo-wide rg: csrfToken / csrftoken patterns ==="
rg -n -i 'csrftoken|csrfToken|x-csrf|xsrf' --hidden --glob '!*node_modules/*'

echo
echo "=== repo-wide rg: content-type enforcement for JSON (req.is / Content-Type checks) ==="
rg -n -i "content-type|application\/json|req\.is\([^)]*json|req\.get\(['\"]Content-Type['\"]\)" --hidden --glob '!*node_modules/*'

echo
echo "=== repo-wide rg: route handlers defined on router.(post|put|patch|delete) ==="
rg -n "router\.(post|put|patch|delete)\(" --hidden --glob '!*node_modules/*' --type=js

Repository: GitMetricsLab/github_tracker

Length of output: 2518


🏁 Script executed:

#!/bin/bash
set -u
shopt -s globstar

echo "=== backend/routes tree (js) ==="
find backend/routes -type f -maxdepth 3 2>/dev/null || true
echo
echo "=== backend/validators tree (js) ==="
find backend/validators -type f -maxdepth 3 2>/dev/null || true
echo

echo "=== repo-wide rg: CSRF middleware usage (csurf/csrf) ==="
rg -n -i 'csurf|csrf' --hidden --glob '!*node_modules/*' || true

echo
echo "=== repo-wide rg: csrfToken / csrftoken patterns ==="
rg -n -i 'csrftoken|csrfToken|x-csrf|xsrf' --hidden --glob '!*node_modules/*' || true

echo
echo "=== repo-wide rg: Content-Type / JSON-only enforcement ==="
rg -n -i "content-type|application\/json|req\.is\([^)]*json|req\.get\(['\"]Content-Type['\"]\)" --hidden --glob '!*node_modules/*' --type=js || true

echo
echo "=== repo-wide rg: mutation route definitions ==="
rg -n "router\.(post|put|patch|delete)\(" backend --hidden --glob '!*node_modules/*' --type=js || true

echo
echo "=== backend/server.js: confirm middleware order ==="
cat -n backend/server.js | sed -n '25,90p'

Repository: GitMetricsLab/github_tracker

Length of output: 2038


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== backend/routes/auth.js ==="
cat -n backend/routes/auth.js

echo
echo "=== backend/validators/validationRequest.js ==="
cat -n backend/validators/validationRequest.js

echo
echo "=== backend/validators/authValidator.js ==="
cat -n backend/validators/authValidator.js

echo
echo "=== repo-wide: search for Content-Type enforcement patterns (simple) ==="
rg -n "Content-Type|application/json|req\.is\(|req\.get\(" backend --hidden --glob '!*node_modules/*' --type=js || true

echo
echo "=== repo-wide: search for csurf/csrf tokens (simple) ==="
rg -n -i "csurf|csrfToken|xsrf|csrftoken|x-csrf" backend --hidden --glob '!*node_modules/*' --type=js || true

Repository: GitMetricsLab/github_tracker

Length of output: 4345


Add CSRF protection for cross-site session cookies (sameSite: "none")

backend/server.js sets express-session to sameSite: "none" in production (with secure enabled), which sends the session cookie on cross-site requests. The repo has no CSRF middleware/tokens (csurf/csrfToken/csrftoken etc. all missing), and the only auth routes are state-changing without CSRF checks: POST /api/auth/signup, POST /api/auth/login, and GET /api/auth/logout. CORS origin restriction does not mitigate CSRF for cookie-based requests.

  • Implement CSRF protection (e.g., csurf or double-submit tokens) for all state-changing endpoints (at least login/logout/signup)
  • Change logout from GET to a non-GET method and protect it with CSRF
  • Set cookie.httpOnly: true explicitly for defense-in-depth
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/server.js` around lines 36 - 40, Update session cookie config and add
CSRF middleware: set cookie.httpOnly: true in the express-session config
(alongside secure and sameSite) and install/use csurf (or implement
double-submit tokens) to protect state-changing routes; mount csurf middleware
(or token validation) for the auth routes (functions/handlers handling POST
/api/auth/signup and POST /api/auth/login and the logout handler) and ensure the
CSRF token is issued to the client (e.g., via a secure sameSite cookie or a
/api/csrf-token endpoint) so the client can include it on requests; change the
logout route from GET /api/auth/logout to a non-GET method (e.g., POST) and
enforce CSRF verification in the logout handler as well.

}));
app.use(passport.initialize());
app.use(passport.session());
Expand Down
Loading