Skip to content

feat: add security middleware and rate limiting#323

Open
DineshSivalanka wants to merge 2 commits into
GitMetricsLab:mainfrom
DineshSivalanka:backend-security-fix
Open

feat: add security middleware and rate limiting#323
DineshSivalanka wants to merge 2 commits into
GitMetricsLab:mainfrom
DineshSivalanka:backend-security-fix

Conversation

@DineshSivalanka
Copy link
Copy Markdown

@DineshSivalanka DineshSivalanka commented May 19, 2026

Related Issue


Description

Added backend security improvements and middleware enhancements to improve API protection and application security.

Implemented:

  • Helmet middleware for secure HTTP headers
  • Express Rate Limiting to prevent API abuse
  • Improved secure CORS configuration using allowed origin whitelist
  • Enhanced session cookie security settings
  • Added frontend URL environment variable support
  • Improved development warnings for missing environment variables

How Has This Been Tested?

  • Tested locally using npm run dev
  • Verified backend server starts successfully
  • Tested API endpoints after enabling middleware
  • Confirmed CORS allows configured frontend origins
  • Verified rate limiting works correctly
  • Checked session configuration functionality
  • Verified no build/runtime errors

Screenshots (if applicable)

N/A


Type of Change

  • Bug fix
  • New feature
  • Code style update
  • Breaking change
  • Documentation update

Summary by CodeRabbit

  • New Features

    • Added rate limiting to API endpoints.
  • Improvements

    • Enhanced CORS configuration with origin allowlisting from environment variables.
    • Improved session security with stricter cookie options.
    • Improved MongoDB connection handling with default configuration.
  • Chores

    • Updated backend dependencies.
    • Added CLIENT_URL environment variable configuration.

Review Change Stack

@netlify
Copy link
Copy Markdown

netlify Bot commented May 19, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit 7e32ad9
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a0be8cc88b26000087a516c
😎 Deploy Preview https://deploy-preview-323--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

Warning

Rate limit exceeded

@DineshSivalanka has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 31 minutes and 6 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 253cb7d6-5c0b-4eef-b224-69ad0197e4da

📥 Commits

Reviewing files that changed from the base of the PR and between 694924e and 7e32ad9.

📒 Files selected for processing (1)
  • backend/server.js
📝 Walkthrough

Walkthrough

This PR implements centralized production security hardening for the backend Express server. Environment configuration and npm dependencies are updated to introduce Helmet security headers and API rate limiting. CORS is switched from permissive to allowlist-based origin validation, and session cookies are hardened with secure attributes. The server startup flow is improved with environment validation and sensible defaults for database connection and port configuration.

Changes

Production Security Hardening for Backend

Layer / File(s) Summary
Environment Configuration and Security Dependencies
backend/.env.sample, backend/package.json
Frontend domain is configured via CLIENT_URL in the environment file. npm dependencies add helmet and express-rate-limit with updated versions of cors and express-session.
Helmet and Rate Limiting Middleware
backend/server.js
helmet() is applied globally to set security headers (CSP, X-Frame-Options, HSTS, etc.). An IP-based rate limiter with 15-minute window and 100-request threshold is mounted on /api to prevent brute-force attacks.
CORS Allowlisting and Session Security
backend/server.js
CORS origin validation replaces permissive wildcard with allowlist derived from ALLOWED_ORIGINS or CLIENT_URL (defaults to localhost:5173). Session cookies are hardened with httpOnly, secure (production), sameSite: 'lax', and 1-day maxAge.
Passport Integration and Server Startup
backend/server.js
Passport initialization and session middleware are wired to the Express app. Auth routes are mounted at /api/auth. MongoDB connection and server listen use PORT (default 5000) and MONGO_URI (defaults to local GitHub tracker DB) with validation warnings for missing configuration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit hops through security gates,
Helmets gleaming, rate limiters wait,
CORS whispers of origins pure,
Sessions encrypted, safe and secure,
From frontend to MongoDB's nest,
This backend is hardened for the test!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add security middleware and rate limiting' accurately summarizes the main changes: security middleware (Helmet) and rate limiting additions.
Description check ✅ Passed The description follows the template structure with all required sections completed: Related Issue, Description, How Has This Been Tested, Type of Change, and testing details are provided.
Linked Issues check ✅ Passed The PR successfully implements most core requirements from issue #322: Helmet security headers, rate limiting, improved CORS with origin allowlisting, secure session cookies, and environment variable validation are all present.
Out of Scope Changes check ✅ Passed All changes relate to security hardening objectives: environment variable configuration, dependency updates for security packages, and middleware enhancements are all within scope of issue #322.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with 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.

Inline comments:
In `@backend/server.js`:
- Around line 73-80: The code currently falls back to insecure defaults (secret:
'dev-secret' and a localhost MONGO_URI) regardless of environment; update the
startup logic so that sessionSecret (SESSION_SECRET) and MONGO_URI are required
when NODE_ENV !== 'development' (or when not running on localhost), logging an
error and exiting process if missing, while preserving the existing dev-only
defaults only when NODE_ENV === 'development'; specifically, change the session
setup that references sessionSecret (used in app.use(session({...}))) to fail
fast in non-development, and apply the same check to wherever MONGO_URI /
mongoUri is read and passed to your Mongo connection function (e.g.,
mongoose.connect or connectToMongo) so the server aborts start when running in
production without those env vars.
- Around line 20-32: Set Express trust proxy before any middleware that depends
on the client IP or secure cookies: call app.set('trust proxy', 1) (or
appropriate trust value) before creating/using the rate limiter (the limiter/
rateLimit config) and before initializing the session middleware (the session
configuration that contains secure: true). Update the startup order so the call
to app.set('trust proxy', ...) appears above the Helmet line or at least before
the limiter variable and the session setup, ensuring rateLimit sees the real
client IP and the session cookie secure flag works correctly behind a reverse
proxy.
- Around line 79-89: The session middleware is using express-session's default
MemoryStore (app.use(session(...))) which is unsafe for production; replace it
with a production-ready store by configuring the session middleware to use a
store instance (e.g., RedisStore from connect-redis, MongoStore from
connect-mongo, or MemoryStore with pruning) and passing it as the store option
to session({ store, secret: sessionSecret || 'dev-secret', ... }); initialize
the chosen store client (e.g., new RedisClient or MongoClient) before creating
the session middleware, wire it into the existing app.use(session(...)) call,
and ensure sessionSecret and cookie settings remain unchanged while adding
graceful error handling for store connection failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 58b9520d-8d20-4645-bdd5-953ec2e3072c

📥 Commits

Reviewing files that changed from the base of the PR and between 8d17610 and 694924e.

📒 Files selected for processing (3)
  • backend/.env.sample
  • backend/package.json
  • backend/server.js

Comment thread backend/server.js
Comment thread backend/server.js
Comment thread backend/server.js
Comment on lines 79 to 89
app.use(session({
secret: process.env.SESSION_SECRET,
secret: sessionSecret || 'dev-secret',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 1000 * 60 * 60 * 24, // 1 day
},
}));
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot May 19, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

cat -n backend/server.js | sed -n '70,100p'

Repository: GitMetricsLab/github_tracker

Length of output: 976


🏁 Script executed:

rg -i "store.*session|session.*store|MemoryStore" backend/

Repository: GitMetricsLab/github_tracker

Length of output: 152


🏁 Script executed:

cat backend/package.json | head -50

Repository: GitMetricsLab/github_tracker

Length of output: 743


🏁 Script executed:

rg "session\(" backend/ -A 5 -B 2

Repository: GitMetricsLab/github_tracker

Length of output: 646


🏁 Script executed:

rg "require.*session|import.*session" backend/

Repository: GitMetricsLab/github_tracker

Length of output: 134


🌐 Web query:

express-session MemoryStore default production warning documentation

💡 Result:

The express-session middleware uses MemoryStore as its default session storage, which is explicitly documented as not designed for production environments [1][2]. The official documentation provides the following warning: "Warning: The default server-side session storage, MemoryStore, is purposely not designed for a production environment. It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing" [1][2]. Key reasons for this warning include: - Memory Leaks: The default MemoryStore does not have a robust mechanism to prune expired sessions, leading to memory accumulation over time [3][4][5]. - Lack of Scalability: Because it stores sessions in the memory of a single Node.js process, it cannot be shared across multiple server instances or processes [1][2][6]. - Data Persistence: All session data is lost if the Node.js process restarts [3]. To address this in production, developers are advised to use a compatible, production-ready session store [1][7]. A common community-recommended solution for those who still require an in-memory store but need to avoid memory leaks is the 'memorystore' package, which implements automatic pruning of expired sessions [3][4][5]. For distributed or highly scalable applications, external stores such as Redis or databases (e.g., MongoDB) are standard practice [3][8][6].

Citations:


Avoid the default in-process session store.

Because no store is configured on line 79, this uses express-session's default MemoryStore. The official documentation explicitly warns it is not designed for production, leaks memory, does not scale past a single process, and loses all session data on restart. Once this app runs on multiple instances, auth state will be lost and memory will accumulate over time.

Use a production-ready session store such as Redis, MongoDB (via connect-mongo), or memorystore with automatic expiration pruning.

🤖 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 79 - 89, The session middleware is using
express-session's default MemoryStore (app.use(session(...))) which is unsafe
for production; replace it with a production-ready store by configuring the
session middleware to use a store instance (e.g., RedisStore from connect-redis,
MongoStore from connect-mongo, or MemoryStore with pruning) and passing it as
the store option to session({ store, secret: sessionSecret || 'dev-secret', ...
}); initialize the chosen store client (e.g., new RedisClient or MongoClient)
before creating the session middleware, wire it into the existing
app.use(session(...)) call, and ensure sessionSecret and cookie settings remain
unchanged while adding graceful error handling for store connection failures.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the review and suggestion.

I agree that a production-ready session store such as Redis or connect-mongo would be more suitable for scalable production deployments. However, since this PR is focused on introducing the initial security middleware improvements and production validation checks, I’d prefer to keep session store migration as a separate enhancement to avoid significantly expanding the scope of this contribution.

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.

@DineshSivalanka, that's a fair call — keeping this PR focused on the core security middleware improvements is a reasonable scoping decision. The MemoryStore concern is real but non-blocking for the initial hardening step.

Would you like me to open a follow-up GitHub issue to track the session store migration (e.g., connect-mongo or Redis) so it doesn't get lost? I can link it back to this PR for context.

🐇 _/_
( ´ω`)
/ >🎫 follow-up issue incoming?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🚀 Feature: Production Security Hardening: Centralized Security Middleware Suite

1 participant