GuardAPI Logo
GuardAPI

Fix Broken User Authentication in Sails

Broken Authentication in Sails.js often stems from weak credential storage, lack of rate limiting, and insecure session management. As an AppSec researcher, I see developers relying on plaintext comparisons or obsolete algorithms like MD5. To harden a Sails app, you must implement strong password hashing (Argon2 or Bcrypt), enforce secure session cookies, and prevent user enumeration.

The Vulnerable Pattern

// api/controllers/AuthController.js
module.exports = {
  login: async function (req, res) {
    const { email, password } = req.body;
    const user = await User.findOne({ email });
    // VULNERABILITY: Plaintext comparison and user enumeration risk
    if (!user) return res.status(404).send('User not found');
    if (user.password === password) {
      req.session.userId = user.id;
      return res.ok();
    }
    return res.status(401).send('Wrong password');
  }
};

The Secure Implementation

The secure implementation fixes three critical flaws. First, it replaces plaintext comparison with Bcrypt, which is computationally expensive and resistant to brute-force. Second, it returns a generic error message regardless of whether the email or password was wrong, stopping attackers from mapping valid accounts. Third, it assumes the session configuration (config/session.js) is hardened with 'httpOnly' to block XSS-based cookie theft and 'secure' to ensure cookies only travel over HTTPS. Additionally, always implement a 'beforeCreate' hook in the User model to hash passwords before they ever touch the database.

// api/controllers/AuthController.js
const bcrypt = require('bcrypt');

module.exports = { login: async function (req, res) { const { email, password } = req.body; // 1. Use a generic error message to prevent enumeration const genericError = ‘Invalid email or password’;

try {
  const user = await User.findOne({ email });
  if (!user) return res.forbidden(genericError);

  // 2. Use bcrypt.compare to mitigate timing attacks and handle hashes
  const isMatch = await bcrypt.compare(password, user.password);
  if (!isMatch) return res.forbidden(genericError);

  // 3. Regenerate session to prevent fixation
  req.session.userId = user.id;
  
  // Ensure config/session.js has: cookie: { secure: true, httpOnly: true, sameSite: 'strict' }
  return res.ok({ message: 'Authenticated' });
} catch (err) {
  return res.serverError(err);
}

} };

System Alert • ID: 6966
Target: Sails API
Potential Vulnerability

Your Sails API might be exposed to Broken User Authentication

74% of Sails apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

Free Tier • No Credit Card • Instant Report

Verified by Ghost Labs Security Team

This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.