CWE-307
AllowedImproper Restriction of Excessive Authentication Attempts
Abstraction: Base · Status: Draft
The product does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame.
1033 vulnerabilities reference this CWE, most recent first.
GHSA-2R78-2MM9-HW6H
Vulnerability from github – Published: 2025-11-18 15:30 – Updated: 2025-12-05 15:30Windu CMS implements weak client-side brute-force protection by using parameter loginError. Information about attempt count or timeout is not stored on the server, which allows a malicious attacker to bypass this brute-force protection by resetting this parameter.
The vendor was notified early about this vulnerability, but didn't respond with the details of vulnerability or vulnerable version range. Only version 4.1 was tested and confirmed as vulnerable, other versions were not tested and might also be vulnerable.
{
"affected": [],
"aliases": [
"CVE-2025-59113"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-11-18T15:16:33Z",
"severity": "MODERATE"
},
"details": "Windu CMS implements weak client-side brute-force protection by using parameter loginError.\u00a0Information about attempt count or timeout is not stored on the server, which allows a malicious attacker to bypass this brute-force protection by resetting this parameter.\n\nThe vendor was notified early about this vulnerability, but didn\u0027t respond with the details of vulnerability or vulnerable version range. Only version 4.1 was tested and confirmed as vulnerable, other versions were not tested and might also be vulnerable.",
"id": "GHSA-2r78-2mm9-hw6h",
"modified": "2025-12-05T15:30:24Z",
"published": "2025-11-18T15:30:56Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-59113"
},
{
"type": "WEB",
"url": "https://cert.pl/posts/2025/11/CVE-2025-59110"
},
{
"type": "WEB",
"url": "https://windu.org"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-2RGV-5M49-97J4
Vulnerability from github – Published: 2026-05-12 06:31 – Updated: 2026-05-12 06:31** UNSUPPORTED WHEN ASSIGNED ** An improper restriction of excessive authentication attempts vulnerability in the web management interface of Zyxel WRE6505 v2 firmware version V1.00(ABDV.3)C0 could allow an adjacent attacker on the LAN to brute-force the password and bypass authentication.
{
"affected": [],
"aliases": [
"CVE-2026-7255"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-05-12T04:16:29Z",
"severity": "MODERATE"
},
"details": "** UNSUPPORTED WHEN ASSIGNED ** An improper restriction of excessive authentication attempts vulnerability in the web management interface of Zyxel WRE6505 v2 firmware version V1.00(ABDV.3)C0 could allow an adjacent attacker on the LAN to brute-force the password and bypass authentication.",
"id": "GHSA-2rgv-5m49-97j4",
"modified": "2026-05-12T06:31:39Z",
"published": "2026-05-12T06:31:39Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-7255"
},
{
"type": "WEB",
"url": "https://www.zyxel.com/global/en/support/end-of-life"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-2RM2-VWH2-FP52
Vulnerability from github – Published: 2022-05-13 01:34 – Updated: 2022-05-13 01:34Cloud Foundry UAA, all versions prior to 4.20.0 and Cloud Foundry UAA Release, all versions prior to 61.0, allows brute forcing of MFA codes. A remote unauthenticated malicious user in possession of a valid username and password can brute force MFA to login as the targeted user.
{
"affected": [],
"aliases": [
"CVE-2018-11082"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2018-10-05T21:29:00Z",
"severity": "CRITICAL"
},
"details": "Cloud Foundry UAA, all versions prior to 4.20.0 and Cloud Foundry UAA Release, all versions prior to 61.0, allows brute forcing of MFA codes. A remote unauthenticated malicious user in possession of a valid username and password can brute force MFA to login as the targeted user.",
"id": "GHSA-2rm2-vwh2-fp52",
"modified": "2022-05-13T01:34:51Z",
"published": "2022-05-13T01:34:51Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-11082"
},
{
"type": "WEB",
"url": "https://www.cloudfoundry.org/blog/cve-2018-11082"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-2VGG-9H6W-M454
Vulnerability from github – Published: 2024-03-18 20:29 – Updated: 2024-03-22 20:05Summary
An attacker can effectively bypass the rate limit and brute force protections by exploiting the application's weak cache-based mechanism. This loophole in security can be combined with other vulnerabilities to attack the default admin account. This flaw undermines a previously patched CVE intended to protect against brute-force attacks.
Details
The application's brute force protection relies on a cache mechanism that tracks login attempts for each user. This cache is limited to a defaultMaxCacheSize of 1000 entries. An attacker can overflow this cache by bombarding it with login attempts for different users, thereby pushing out the admin account's failed attempts and effectively resetting the rate limit for that account.
The brute force protection mechanism's code:
if failed && len(failures) >= getMaximumCacheSize() {
log.Warnf("Session cache size exceeds %d entries, removing random entry",
getMaximumCacheSize())
idx := rand.Intn(len(failures) - 1)
var rmUser string
i := 0
for key := range failures {
if i == idx {
rmUser = key
delete(failures, key)
break
}
i++ }
log.Infof("Deleted entry for user %s from cache", rmUser)
}
PoC
- Set up the application environment and identify the login page.
- Execute 4 failed login attempts for the admin account.
- Run a Burp Intruder attack to populate the cache with login attempts for usernames ranging from 1 to 10000.
- After 1000 attempts, start monitoring to see if the admin entries in the cache have been cleared.
- At this point, brute-force the admin account.
In just 15 minutes, the PoC was able to perform 230 brute force attempts on the admin account. This rate allows for approximately 1000 requests per hour, effectively rendering the older CVE rate limit patches useless.
Impact
This is a severe vulnerability that enables attackers to perform brute force attacks at an accelerated rate, especially targeting the default admin account.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/argoproj/argo-cd/v2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.8.13"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/argoproj/argo-cd/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.9.0"
},
{
"fixed": "2.9.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/argoproj/argo-cd/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.10.0"
},
{
"fixed": "2.10.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-21662"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": true,
"github_reviewed_at": "2024-03-18T20:29:05Z",
"nvd_published_at": "2024-03-18T19:15:06Z",
"severity": "MODERATE"
},
"details": "### Summary\nAn attacker can effectively bypass the rate limit and brute force protections by exploiting the application\u0027s weak cache-based mechanism. This loophole in security can be combined with other vulnerabilities to attack the default admin account. This flaw undermines a previously [patched CVE](https://argo-cd.readthedocs.io/en/stable/security_considerations/#cve-2020-8827-insufficient-anti-automationanti-brute-force) intended to protect against brute-force attacks.\n\n### Details\nThe application\u0027s brute force protection relies on a cache mechanism that tracks login attempts for each user. This cache is limited to a `defaultMaxCacheSize` of 1000 entries. An attacker can overflow this cache by bombarding it with login attempts for different users, thereby pushing out the admin account\u0027s failed attempts and effectively resetting the rate limit for that account.\n\nThe brute force protection mechanism\u0027s code:\n```go\n if failed \u0026\u0026 len(failures) \u003e= getMaximumCacheSize() {\n log.Warnf(\"Session cache size exceeds %d entries, removing random entry\",\n\ngetMaximumCacheSize())\n idx := rand.Intn(len(failures) - 1)\n var rmUser string\n i := 0\n for key := range failures {\n\n if i == idx {\n rmUser = key\n\n delete(failures, key)\n\nbreak\n\n}\n\ni++ }\n\n log.Infof(\"Deleted entry for user %s from cache\", rmUser)\n }\n```\n\n### PoC\n1. Set up the application environment and identify the login page.\n2. Execute 4 failed login attempts for the admin account.\n3. Run a Burp Intruder attack to populate the cache with login attempts for usernames ranging from 1 to 10000.\n4. After 1000 attempts, start monitoring to see if the admin entries in the cache have been cleared.\n5. At this point, brute-force the admin account.\n\nIn just 15 minutes, the PoC was able to perform 230 brute force attempts on the admin account. This rate allows for approximately 1000 requests per hour, effectively rendering the [older CVE](https://argo-cd.readthedocs.io/en/stable/security_considerations/#cve-2020-8827-insufficient-anti-automationanti-brute-force) rate limit patches useless.\n\n### Impact\nThis is a severe vulnerability that enables attackers to perform brute force attacks at an accelerated rate, especially targeting the default admin account.",
"id": "GHSA-2vgg-9h6w-m454",
"modified": "2024-03-22T20:05:14Z",
"published": "2024-03-18T20:29:05Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/argoproj/argo-cd/security/advisories/GHSA-2vgg-9h6w-m454"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-21662"
},
{
"type": "WEB",
"url": "https://github.com/argoproj/argo-cd/commit/17b0df1168a4c535f6f37e95f25ed7cd81e1fa4d"
},
{
"type": "WEB",
"url": "https://github.com/argoproj/argo-cd/commit/6e181d72b31522f886a2afa029d5b26d7912ec7b"
},
{
"type": "WEB",
"url": "https://github.com/argoproj/argo-cd/commit/cebb6538f7944c87ca2fecb5d17f8baacc431456"
},
{
"type": "WEB",
"url": "https://argo-cd.readthedocs.io/en/stable/security_considerations/#cve-2020-8827-insufficient-anti-automationanti-brute-force"
},
{
"type": "PACKAGE",
"url": "https://github.com/argoproj/argo-cd"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Bypassing Rate Limit and Brute Force Protection Using Cache Overflow"
}
GHSA-2WP6-XHP6-G2GW
Vulnerability from github – Published: 2026-02-27 00:31 – Updated: 2026-03-05 21:30The WebSocket Application Programming Interface lacks restrictions on the number of authentication requests. This absence of rate limiting may allow an attacker to conduct denial-of-service attacks by suppressing or mis-routing legitimate charger telemetry, or conduct brute-force attacks to gain unauthorized access.
{
"affected": [],
"aliases": [
"CVE-2026-25113"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-02-27T00:16:56Z",
"severity": "HIGH"
},
"details": "The WebSocket Application Programming Interface lacks restrictions on \nthe number of authentication requests. This absence of rate limiting may\n allow an attacker to conduct denial-of-service attacks by suppressing \nor mis-routing legitimate charger telemetry, or conduct brute-force \nattacks to gain unauthorized access.",
"id": "GHSA-2wp6-xhp6-g2gw",
"modified": "2026-03-05T21:30:27Z",
"published": "2026-02-27T00:31:45Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25113"
},
{
"type": "WEB",
"url": "https://github.com/cisagov/CSAF/blob/develop/csaf_files/OT/white/2026/icsa-26-057-06.json"
},
{
"type": "WEB",
"url": "https://swtchenergy.com/contact"
},
{
"type": "WEB",
"url": "https://www.cisa.gov/news-events/ics-advisories/icsa-26-057-06"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-2X6P-VP7X-P4WG
Vulnerability from github – Published: 2023-08-28 03:30 – Updated: 2024-04-04 07:13IBM Security Guardium Data Encryption (IBM Guardium Cloud Key Manager (GCKM) 1.10.3)) uses an inadequate account lockout setting that could allow a remote attacker to brute force account credentials. IBM X-Force ID: 248126.
{
"affected": [],
"aliases": [
"CVE-2023-26271"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-08-28T01:15:09Z",
"severity": "HIGH"
},
"details": "IBM Security Guardium Data Encryption (IBM Guardium Cloud Key Manager (GCKM) 1.10.3)) uses an inadequate account lockout setting that could allow a remote attacker to brute force account credentials. IBM X-Force ID: 248126.",
"id": "GHSA-2x6p-vp7x-p4wg",
"modified": "2024-04-04T07:13:50Z",
"published": "2023-08-28T03:30:12Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-26271"
},
{
"type": "WEB",
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/248126"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/6995161"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-2XPH-9RQM-66CR
Vulnerability from github – Published: 2026-02-27 00:31 – Updated: 2026-03-05 21:30The WebSocket Application Programming Interface lacks restrictions on the number of authentication requests. This absence of rate limiting may allow an attacker to conduct denial-of-service attacks by suppressing or mis-routing legitimate charger telemetry, or conduct brute-force attacks to gain unauthorized access.
{
"affected": [],
"aliases": [
"CVE-2026-25114"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-02-27T00:16:57Z",
"severity": "HIGH"
},
"details": "The WebSocket Application Programming Interface lacks restrictions on \nthe number of authentication requests. This absence of rate limiting may\n allow an attacker to conduct denial-of-service attacks by suppressing \nor mis-routing legitimate charger telemetry, or conduct brute-force \nattacks to gain unauthorized access.",
"id": "GHSA-2xph-9rqm-66cr",
"modified": "2026-03-05T21:30:27Z",
"published": "2026-02-27T00:31:46Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25114"
},
{
"type": "WEB",
"url": "https://cloudcharge.tech/support/contact"
},
{
"type": "WEB",
"url": "https://github.com/cisagov/CSAF/blob/develop/csaf_files/OT/white/2026/icsa-26-057-03.json"
},
{
"type": "WEB",
"url": "https://www.cisa.gov/news-events/ics-advisories/icsa-26-057-03"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-2XWJ-VC46-67HJ
Vulnerability from github – Published: 2024-06-10 18:31 – Updated: 2024-06-10 18:31Improper Restriction of Excessive Authentication Attempts vulnerability in wpdevart Contact Form Builder, Contact Widget allows Functionality Bypass.This issue affects Contact Form Builder, Contact Widget: from n/a through 2.1.7.
{
"affected": [],
"aliases": [
"CVE-2024-35747"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-06-10T17:16:30Z",
"severity": "MODERATE"
},
"details": "Improper Restriction of Excessive Authentication Attempts vulnerability in wpdevart Contact Form Builder, Contact Widget allows Functionality Bypass.This issue affects Contact Form Builder, Contact Widget: from n/a through 2.1.7.",
"id": "GHSA-2xwj-vc46-67hj",
"modified": "2024-06-10T18:31:09Z",
"published": "2024-06-10T18:31:09Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-35747"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/vulnerability/contact-forms-builder/wordpress-contact-form-builder-contact-widget-plugin-2-1-7-bypass-vulnerability-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-2XWV-25CQ-66XR
Vulnerability from github – Published: 2025-05-12 18:31 – Updated: 2025-05-13 18:30An issue in the userId parameter in the change password function of Flytxt NEON-dX v0.0.1-SNAPSHOT-6.9-qa-2-9-g5502a0c allows attackers to execute brute force attacks to discover user passwords.
{
"affected": [],
"aliases": [
"CVE-2023-34732"
],
"database_specific": {
"cwe_ids": [
"CWE-307"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-05-12T18:15:43Z",
"severity": "MODERATE"
},
"details": "An issue in the userId parameter in the change password function of Flytxt NEON-dX v0.0.1-SNAPSHOT-6.9-qa-2-9-g5502a0c allows attackers to execute brute force attacks to discover user passwords.",
"id": "GHSA-2xwv-25cq-66xr",
"modified": "2025-05-13T18:30:50Z",
"published": "2025-05-12T18:31:48Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-34732"
},
{
"type": "WEB",
"url": "https://github.com/saykino/CVE-2023-34732"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-32GC-64M7-HJ7V
Vulnerability from github – Published: 2026-09-22 16:34 – Updated: 2026-09-22 16:34Summary
9router enforces a progressive login lockout (5 failed attempts → temporary 30s+ lock) keyed on the client IP. The client IP used for this limiter is taken from the X-9r-Real-Ip request header, which is intended to be set only by the bundled custom-server.js layer from the unspoofable TCP socket address. In deployment modes where requests reach Next.js directly, a remote attacker controls this header and can assign a unique value to every request. Because each distinct header value maps to a fresh limiter bucket, the lockout never triggers, enabling unlimited password guessing against the dashboard login endpoint. This was reproduced against a live instance: a fixed header value was locked out (429) after 5 attempts, while rotating the header produced unlimited 401 responses with no lockout.
Affected Component
src/lib/auth/loginLimiter.jsgetClientIp()— derives the rate-limit bucket key from the client-suppliedX-9r-Real-IpheadercheckLock()/recordFail()— per-IP progressive lockout (MAX_FAILS_BEFORE_LOCK = 5)src/app/api/auth/login/route.js— login endpoint protected by the above limiter
Root Cause
The brute-force protection partitions failed-attempt counters by client IP, but obtains that IP from a client-controllable HTTP header rather than from the transport layer. getClientIp() returns the value of X-9r-Real-Ip directly. The design assumes this header is produced and sanitized only by the trusted custom-server.js wrapper. When the application is served without that wrapper, the header passes through unmodified, so the attacker chooses the bucket key. Since the lockout is per-bucket, assigning a new value per request keeps every counter below the threshold:
Untrusted Client Input
↓
X-9r-Real-Ip: <attacker-chosen, rotated each request>
↓
getClientIp() → distinct bucket per request
↓
recordFail()/checkLock() → threshold (5) never reached
↓
unlimited 401 attempts, no 429 lockout
Attack Scenario
-
The instance is deployed in a mode that does not use
custom-server.js, and the login endpoint is reachable by the attacker (the default bind is0.0.0.0). -
The attacker submits password guesses to
POST /api/auth/login, setting a differentX-9r-Real-Ipvalue on each request (e.g.,10.0.0.1,10.0.0.2, ...). -
Each request is counted against a new bucket, so the limiter always reports remaining attempts and never returns
429. -
The attacker continues guessing without throttling until the dashboard password is recovered, yielding an authenticated admin session.
Proof of Concept
Baseline — fixed header value (lockout enforced)
Repeated POST /api/auth/login with a constant X-9r-Real-Ip: 9.9.9.9 and body {"password":"wrong"}:
POST /api/auth/login HTTP/1.1
Host: victim.example.com:20127
X-9r-Real-Ip: 9.9.9.9
Content-Type: application/json
Content-Length: 20
Connection: close
{"password":"wrong"}
Observed responses (sequential):
#1 → 401 {"error":"Invalid password. 4 attempt(s) left before lockout.","remainingBeforeLock":4}
#2 → 401 {"error":"Invalid password. 3 attempt(s) left before lockout.","remainingBeforeLock":3}
#3 → 401 {"error":"Invalid password. 2 attempt(s) left before lockout.","remainingBeforeLock":2}
#4 → 401 {"error":"Invalid password. 1 attempt(s) left before lockout.","remainingBeforeLock":1}
#5 → 429 Retry-After: 30
{"error":"Too many failed attempts. Try again in 30s. ...","retryAfter":30}
Exploit — rotated header value (lockout bypassed)
Same request and body, but a different X-9r-Real-Ip per request, sent while 9.9.9.9 was already locked:
POST /api/auth/login HTTP/1.1
Host: victim.example.com:20127
X-9r-Real-Ip: 10.0.0.1
Content-Type: application/json
Content-Length: 20
Connection: close
{"password":"wrong"}
Observed responses:
X-9r-Real-Ip: 10.0.0.1 → 401 {"error":"Invalid password. 4 attempt(s) left before lockout.","remainingBeforeLock":4}
X-9r-Real-Ip: 10.0.0.2 → 401 {"error":"Invalid password. 4 attempt(s) left before lockout.","remainingBeforeLock":4}
X-9r-Real-Ip: 10.0.0.3 → 401 {"error":"Invalid password. 4 attempt(s) left before lockout.","remainingBeforeLock":4}
Every rotated value resets to "4 attempt(s) left" and never returns 429, demonstrating unbounded guessing.
Impact
The login brute-force/credential-stuffing protection can be fully neutralized by a remote, unauthenticated attacker. This permits unlimited password guessing against the dashboard login endpoint, materially increasing the likelihood of account compromise. A recovered password yields an authenticated administrative session over the 9router dashboard and its protected APIs. The bypass is especially impactful given the default network bind (0.0.0.0) and the existence of a default dashboard password, both of which lower the effort required to succeed.
Remediation
- Do not derive the rate-limit key from a client-controllable header. Base
getClientIp()on the transport-level peer address (req.socket.remoteAddress) for the limiter bucket. - Only honor forwarded client-IP headers when they originate from explicitly trusted, configured proxy infrastructure.
- If
custom-server.jsis required for the security model, fail closed when its trusted marker is absent, and strip/reject any inbound client-suppliedX-9r-*headers at the edge before they reach the limiter. - Consider a global (non-bucketed) attempt ceiling and exponential backoff as defense-in-depth so that header manipulation cannot reset all counters.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.5.4"
},
"package": {
"ecosystem": "npm",
"name": "9router"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.5.8"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-56682"
],
"database_specific": {
"cwe_ids": [
"CWE-307",
"CWE-807"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-22T16:34:18Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "# Summary\n\n9router enforces a progressive login lockout (5 failed attempts \u2192 temporary 30s+ lock) keyed on the client IP. The client IP used for this limiter is taken from the X-9r-Real-Ip request header, which is intended to be set only by the bundled custom-server.js layer from the unspoofable TCP socket address. In deployment modes where requests reach Next.js directly, a remote attacker controls this header and can assign a unique value to every request. Because each distinct header value maps to a fresh limiter bucket, the lockout never triggers, enabling unlimited password guessing against the dashboard login endpoint. This was reproduced against a live instance: a fixed header value was locked out (429) after 5 attempts, while rotating the header produced unlimited 401 responses with no lockout.\n\n# Affected Component\n\n- `src/lib/auth/loginLimiter.js`\n - `getClientIp()` \u2014 derives the rate-limit bucket key from the client-supplied `X-9r-Real-Ip` header\n - `checkLock()` / `recordFail()` \u2014 per-IP progressive lockout (`MAX_FAILS_BEFORE_LOCK = 5`)\n- `src/app/api/auth/login/route.js` \u2014 login endpoint protected by the above limiter\n\n# Root Cause\n\nThe brute-force protection partitions failed-attempt counters by client IP, but obtains that IP from a client-controllable HTTP header rather than from the transport layer. `getClientIp()` returns the value of `X-9r-Real-Ip` directly. The design assumes this header is produced and sanitized only by the trusted `custom-server.js` wrapper. When the application is served without that wrapper, the header passes through unmodified, so the attacker chooses the bucket key. Since the lockout is per-bucket, assigning a new value per request keeps every counter below the threshold:\n\n```text\nUntrusted Client Input\n \u2193\nX-9r-Real-Ip: \u003cattacker-chosen, rotated each request\u003e\n \u2193\ngetClientIp() \u2192 distinct bucket per request\n \u2193\nrecordFail()/checkLock() \u2192 threshold (5) never reached\n \u2193\nunlimited 401 attempts, no 429 lockout\n```\n\n# Attack Scenario\n\n1. The instance is deployed in a mode that does not use `custom-server.js`, and the login endpoint is reachable by the attacker (the default bind is `0.0.0.0`).\n\n2. The attacker submits password guesses to `POST /api/auth/login`, setting a different `X-9r-Real-Ip` value on each request (e.g., `10.0.0.1`, `10.0.0.2`, ...).\n\n3. Each request is counted against a new bucket, so the limiter always reports remaining attempts and never returns `429`.\n\n4. The attacker continues guessing without throttling until the dashboard password is recovered, yielding an authenticated admin session.\n\n# Proof of Concept\n\n## Baseline \u2014 fixed header value (lockout enforced)\n\nRepeated `POST /api/auth/login` with a constant `X-9r-Real-Ip: 9.9.9.9` and body `{\"password\":\"wrong\"}`:\n\n```http\nPOST /api/auth/login HTTP/1.1\nHost: victim.example.com:20127\nX-9r-Real-Ip: 9.9.9.9\nContent-Type: application/json\nContent-Length: 20\nConnection: close\n\n{\"password\":\"wrong\"}\n```\n\nObserved responses (sequential):\n\n```text\n#1 \u2192 401 {\"error\":\"Invalid password. 4 attempt(s) left before lockout.\",\"remainingBeforeLock\":4}\n\n#2 \u2192 401 {\"error\":\"Invalid password. 3 attempt(s) left before lockout.\",\"remainingBeforeLock\":3}\n\n#3 \u2192 401 {\"error\":\"Invalid password. 2 attempt(s) left before lockout.\",\"remainingBeforeLock\":2}\n\n#4 \u2192 401 {\"error\":\"Invalid password. 1 attempt(s) left before lockout.\",\"remainingBeforeLock\":1}\n\n#5 \u2192 429 Retry-After: 30\n {\"error\":\"Too many failed attempts. Try again in 30s. ...\",\"retryAfter\":30}\n```\n\n## Exploit \u2014 rotated header value (lockout bypassed)\n\nSame request and body, but a different `X-9r-Real-Ip` per request, sent while `9.9.9.9` was already locked:\n\n```http\nPOST /api/auth/login HTTP/1.1\nHost: victim.example.com:20127\nX-9r-Real-Ip: 10.0.0.1\nContent-Type: application/json\nContent-Length: 20\nConnection: close\n\n{\"password\":\"wrong\"}\n```\n\nObserved responses:\n\n```text\nX-9r-Real-Ip: 10.0.0.1 \u2192 401 {\"error\":\"Invalid password. 4 attempt(s) left before lockout.\",\"remainingBeforeLock\":4}\n\nX-9r-Real-Ip: 10.0.0.2 \u2192 401 {\"error\":\"Invalid password. 4 attempt(s) left before lockout.\",\"remainingBeforeLock\":4}\n\nX-9r-Real-Ip: 10.0.0.3 \u2192 401 {\"error\":\"Invalid password. 4 attempt(s) left before lockout.\",\"remainingBeforeLock\":4}\n```\n\u003cimg width=\"1211\" height=\"814\" alt=\"Screenshot 2026-06-19 183338\" src=\"https://github.com/user-attachments/assets/07e37cf3-1860-4a06-8b27-97a5f6b9be64\" /\u003e\n\u003cimg width=\"1208\" height=\"816\" alt=\"Screenshot 2026-06-19 183408\" src=\"https://github.com/user-attachments/assets/27021c5c-cb29-4649-887e-8de46f4c6e1c\" /\u003e\n\nEvery rotated value resets to `\"4 attempt(s) left\"` and never returns `429`, demonstrating unbounded guessing.\n# Impact\n\nThe login brute-force/credential-stuffing protection can be fully neutralized by a remote, unauthenticated attacker. This permits unlimited password guessing against the dashboard login endpoint, materially increasing the likelihood of account compromise. A recovered password yields an authenticated administrative session over the 9router dashboard and its protected APIs. The bypass is especially impactful given the default network bind (`0.0.0.0`) and the existence of a default dashboard password, both of which lower the effort required to succeed.\n\n# Remediation\n\n- Do not derive the rate-limit key from a client-controllable header. Base `getClientIp()` on the transport-level peer address (`req.socket.remoteAddress`) for the limiter bucket.\n- Only honor forwarded client-IP headers when they originate from explicitly trusted, configured proxy infrastructure.\n- If `custom-server.js` is required for the security model, fail closed when its trusted marker is absent, and strip/reject any inbound client-supplied `X-9r-*` headers at the edge before they reach the limiter.\n- Consider a global (non-bucketed) attempt ceiling and exponential backoff as defense-in-depth so that header manipulation cannot reset all counters.",
"id": "GHSA-32gc-64m7-hj7v",
"modified": "2026-09-22T16:34:18Z",
"published": "2026-09-22T16:34:18Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/decolua/9router/security/advisories/GHSA-32gc-64m7-hj7v"
},
{
"type": "WEB",
"url": "https://github.com/decolua/9router/commit/efd20be8d81ef2e256a7037f3aa78e6b567b5fd3"
},
{
"type": "PACKAGE",
"url": "https://github.com/decolua/9router"
},
{
"type": "WEB",
"url": "https://github.com/decolua/9router/releases/tag/v0.5.6"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "9Router has a Login Brute-Force Lockout Bypass via Spoofable X-9r-Real-Ip Header"
}
Mitigation
- Common protection mechanisms include:
- Disconnecting the user after a small number of failed attempts
- Implementing a timeout
- Locking out a targeted account
- Requiring a computational task on the user's part.
Mitigation MIT-4
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid [REF-1482].
- Consider using libraries with authentication capabilities such as OpenSSL or the ESAPI Authenticator. [REF-45]
CAPEC-16: Dictionary-based Password Attack
An attacker tries each of the words in a dictionary as passwords to gain access to the system via some user's account. If the password chosen by the user was a word within the dictionary, this attack will be successful (in the absence of other mitigations). This is a specific instance of the password brute forcing attack pattern.
Dictionary Attacks differ from similar attacks such as Password Spraying (CAPEC-565) and Credential Stuffing (CAPEC-600), since they leverage unknown username/password combinations and don't care about inducing account lockouts.
CAPEC-49: Password Brute Forcing
An adversary tries every possible value for a password until they succeed. A brute force attack, if feasible computationally, will always be successful because it will essentially go through all possible passwords given the alphabet used (lower case letters, upper case letters, numbers, symbols, etc.) and the maximum length of the password.
CAPEC-560: Use of Known Domain Credentials
An adversary guesses or obtains (i.e. steals or purchases) legitimate credentials (e.g. userID/password) to achieve authentication and to perform authorized actions under the guise of an authenticated user or service.
CAPEC-565: Password Spraying
In a Password Spraying attack, an adversary tries a small list (e.g. 3-5) of common or expected passwords, often matching the target's complexity policy, against a known list of user accounts to gain valid credentials. The adversary tries a particular password for each user account, before moving onto the next password in the list. This approach assists the adversary in remaining undetected by avoiding rapid or frequent account lockouts. The adversary may then reattempt the process with additional passwords, once enough time has passed to prevent inducing a lockout.
CAPEC-600: Credential Stuffing
An adversary tries known username/password combinations against different systems, applications, or services to gain additional authenticated access. Credential Stuffing attacks rely upon the fact that many users leverage the same username/password combination for multiple systems, applications, and services.
CAPEC-652: Use of Known Kerberos Credentials
An adversary obtains (i.e. steals or purchases) legitimate Kerberos credentials (e.g. Kerberos service account userID/password or Kerberos Tickets) with the goal of achieving authenticated access to additional systems, applications, or services within the domain.
CAPEC-653: Use of Known Operating System Credentials
An adversary guesses or obtains (i.e. steals or purchases) legitimate operating system credentials (e.g. userID/password) to achieve authentication and to perform authorized actions on the system, under the guise of an authenticated user or service. This applies to any Operating System.