Skip to main content

Security

Current security status and required improvements for the TrickBook backend.

Critical Issues

Immediate Action Required

The following issues must be addressed before any further development.

1. Exposed Credentials

Status: CRITICAL

The .env file contains plaintext credentials that may be committed to git:

# EXPOSED - Rotate these immediately
ATLAS_URI=mongodb+srv://[REDACTED]@cluster.mongodb.net/...
AWS_KEY=[REDACTED]
AWS_SECRET=[REDACTED]
EMAIL_PASSWORD=[REDACTED]

Fix:

  1. Rotate ALL credentials immediately
  2. Add .env to .gitignore
  3. Use secrets manager (AWS Secrets Manager, Doppler, etc.)
  4. Create .env.example with placeholder values

2. Hardcoded JWT Secret

Status: CRITICAL

// Current code - INSECURE
jwt.sign(payload, "jwtPrivateKey");

Fix:

jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' });

3. No Token Expiration

Status: CRITICAL

JWT tokens never expire, meaning a leaked token grants permanent access.

Fix:

const token = jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: '1h' // Short-lived access token
});

// Implement refresh tokens for better UX
const refreshToken = jwt.sign(
{ _id: user._id },
process.env.REFRESH_SECRET,
{ expiresIn: '7d' }
);

4. End-of-Life Node.js

Status: CRITICAL

Node.js 12.6.x reached end-of-life in April 2022. No security patches available.

Fix:

// package.json
{
"engines": {
"node": ">=18.0.0"
}
}

High Priority Issues

5. Outdated helmet

Current: 3.22.0 (2019) Latest: 7.x

Missing security headers and protections.

Fix:

npm install helmet@latest
const helmet = require('helmet');
app.use(helmet());

6. No Rate Limiting

Login and API endpoints have no protection against brute force attacks.

Fix:

npm install express-rate-limit
const rateLimit = require('express-rate-limit');

// Strict limit for auth endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5,
message: 'Too many login attempts, try again later'
});

router.post('/auth', authLimiter, loginHandler);

// General API limit
const apiLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 100
});

app.use('/api/', apiLimiter);

7. CORS Wildcard

Current:

app.use(cors());  // Allows all origins

Fix:

const corsOptions = {
origin: [
'https://thetrickbook.com',
'https://www.thetrickbook.com',
'https://admin.thetrickbook.com'
],
credentials: true
};

app.use(cors(corsOptions));

8. Unrestricted Public Endpoints

These endpoints expose data without authentication:

EndpointRisk
GET /api/users/allExposes all user emails
GET /api/listings/allExposes all user data
GET /api/spotsMay be intentional

Fix: Add authentication or remove if not needed.


Medium Priority Issues

9. Weak Password Requirements

Current:

password: Joi.string().min(5).required()

Fix:

password: Joi.string()
.min(8)
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
.required()
.messages({
'string.pattern.base': 'Password must contain uppercase, lowercase, and number'
})

10. No Input Sanitization

User input used directly in regex patterns:

// Vulnerable
{ name: { $regex: userInput, $options: "i" } }

Fix:

const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

{ name: { $regex: escapeRegex(userInput), $options: "i" } }

11. Missing HTTPS Redirect

Ensure all traffic uses HTTPS:

app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https') {
return res.redirect(`https://${req.header('host')}${req.url}`);
}
next();
});

12. No Request Size Limits

Large payloads could cause DoS:

app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ limit: '10kb', extended: true }));

Security Checklist

Authentication

  • Move JWT secret to environment variable
  • Add token expiration (1 hour)
  • Implement refresh tokens
  • Add password complexity requirements
  • Add account lockout after failed attempts

Authorization

  • Review all public endpoints
  • Add authentication to /api/users/all
  • Verify admin checks on all admin routes

Network

  • Update CORS whitelist
  • Add rate limiting
  • Enforce HTTPS
  • Add request size limits

Dependencies

  • Upgrade Node.js to 18+
  • Update helmet to 7.x
  • Update jsonwebtoken to 9.x
  • Update joi to 17.x
  • Run npm audit and fix vulnerabilities

Credentials

  • Rotate MongoDB password
  • Rotate AWS access keys
  • Rotate email password
  • Create new JWT secret
  • Add .env to .gitignore
  • Set up secrets manager

Monitoring

  • Add error logging (Winston/Pino)
  • Set up Sentry for error tracking
  • Monitor for suspicious activity
  • Set up alerts for failed auth attempts

Secure Configuration Template

// index.js - Secure setup

const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');

const app = express();

// Security headers
app.use(helmet());

// CORS whitelist
app.use(cors({
origin: ['https://thetrickbook.com'],
credentials: true
}));

// Rate limiting
app.use(rateLimit({
windowMs: 60 * 1000,
max: 100
}));

// Request size limits
app.use(express.json({ limit: '10kb' }));

// HTTPS redirect (behind proxy)
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https') {
return res.redirect(301, `https://${req.header('host')}${req.url}`);
}
next();
});

// Validate required env vars
const required = ['ATLAS_URI', 'JWT_SECRET', 'AWS_KEY'];
required.forEach(key => {
if (!process.env[key]) {
console.error(`Missing required env var: ${key}`);
process.exit(1);
}
});