Skip to content

Implement failed login attempt tracking, account lockout, and exponential backoff delay in login handler to mitigate brute-force attacks.#1591

Open
zeropath-ai-dev[bot] wants to merge 2 commits intomasterfrom
zvuln_fix_natural_language_rule_violation_1755145153960361
Open

Implement failed login attempt tracking, account lockout, and exponential backoff delay in login handler to mitigate brute-force attacks.#1591
zeropath-ai-dev[bot] wants to merge 2 commits intomasterfrom
zvuln_fix_natural_language_rule_violation_1755145153960361

Conversation

@zeropath-ai-dev
Copy link
Copy Markdown

Summary

  • The Vulnerability Description:
    The login handler did not track failed authentication attempts, apply delays, or invoke account lockout after repeated failures, exposing the application to brute-force and credential stuffing attacks.

  • This Fix:
    The patch adds logic to track per-user failed login attempts, trigger lockout after too many failures, and introduce exponential backoff delays for each failed attempt, improving security against automated attacks.

  • The Cause of the Issue:
    The previous code immediately returned a 401 error for failed logins without counting failed attempts, locking accounts, or delaying responses, allowing attackers to try unlimited passwords without deterrence.

  • The Patch Implementation:
    The modified code uses LockoutService to monitor and increment failed login attempts, locks accounts after a threshold (MAX_FAILED_ATTEMPTS), applies exponential delay via setTimeout, and integrates a RateLimiter to further throttle rapid login requests.

Vulnerability Details

  • Vulnerability Class: Natural Language Rule Violation
  • Severity: 6.9
  • Affected File: data/static/codefixes/loginAdminChallenge_2.ts
  • Vulnerable Lines: 34-34

Code Snippets

diff --git a/data/static/codefixes/loginAdminChallenge_2.ts b/data/static/codefixes/loginAdminChallenge_2.ts
index 4a353fcda..0aa2b2be9 100644
--- a/data/static/codefixes/loginAdminChallenge_2.ts
+++ b/data/static/codefixes/loginAdminChallenge_2.ts
@@ -1,4 +1,9 @@
 import {BasketModel} from "../../../models/basket";
+import LockoutService from "../../../services/LockoutService";
+import RateLimiter from "../../../services/RateLimiter";
+
+const MAX_FAILED_ATTEMPTS = 5;
+const BASE_DELAY_MS = 1000;
 
 module.exports = function login () {
   function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) {
@@ -13,7 +18,12 @@ module.exports = function login () {
       })
   }
 
-  return (req: Request, res: Response, next: NextFunction) => {
+  return async (req: Request, res: Response, next: NextFunction) => {
+    try {
+      await RateLimiter.consume(req.ip);
+    } catch (err) {
+      return res.status(429).send(res.__('Too many requests, please try again later.'));
+    }
     models.sequelize.query(`SELECT * FROM Users WHERE email = $1 AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`,
       { bind: [ req.body.email ], model: models.User, plain: true })
       .then((authenticatedUser) => {
@@ -31,9 +41,28 @@ module.exports = function login () {
         } else if (user.data?.id) {
           afterLogin(user, res, next)
         } else {
-          res.status(401).send(res.__('Invalid email or password.'))
+          const identifier = req.body.email || req.ip;
+          // check account lockout status
+          LockoutService.isLocked(identifier)
+            .then((locked: boolean) => {
+              if (locked) {
+                return res.status(403).send(res.__('Account locked due to too many failed login attempts.'));
+              }
+              const attempts = LockoutService.incrementFailedAttempts(identifier);
+              if (attempts >= MAX_FAILED_ATTEMPTS) {
+                LockoutService.lockAccount(identifier);
+                return res.status(403).send(res.__('Account locked due to too many failed login attempts.'));
+              }
+              const delay = BASE_DELAY_MS * Math.pow(2, attempts - 1);
+              setTimeout(() => {
+                res.status(401).send(res.__('Invalid email or password.'));
+              }, delay);
+            })
+            .catch((error: Error) => {
+              next(error);
+            });
         }
       }).catch((error: Error) => {
         next(error)
       })
-  }
\ No newline at end of file
+  }

How to Modify the Patch

You can modify this patch by using one of the two methods outlined below. We recommend using the @zeropath-ai-dev bot for updating the code. If you encounter any bugs or issues with the patch, please report them here.

Ask @zeropath-ai-dev!

To request modifications, please post a comment beginning with @zeropath-ai-dev and specify the changes required.

@zeropath-ai-dev will then implement the requested adjustments and commit them to the specified branch in this pull request. Our bot is capable of managing changes across multiple files and various development-related requests.

Manually Modify the Files

# Checkout created branch:
git checkout zvuln_fix_natural_language_rule_violation_1755145153960361

# if vscode is installed run (or use your favorite editor / IDE):
code data/static/codefixes/loginAdminChallenge_2.ts

# Add, commit, and push changes:
git add -A
git commit -m "Update generated patch with x, y, and z changes."
git push zvuln_fix_natural_language_rule_violation_1755145153960361

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants