Summary
The /admin/auth/login endpoint provides no anti-automation protection: the
captcha verification has been removed (commented out), repeated failures do not
trigger any account lockout, and there is no IP/account-level rate limiting.
An attacker can therefore perform unlimited online brute-force attacks against
administrator credentials and eventually take over the admin backend.
- Type: Authentication protection weakness / Improper Restriction of Excessive Authentication Attempts
- CWE: CWE-307
- Severity: Medium (High when combined with default credentials)
- Component:
litemall-admin-api
Affected Endpoint
POST /admin/auth/login
Source file:
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAuthController.java
Details
1. Captcha verification is commented out
In AdminAuthController.login(...), both the parsing and the comparison of the
code field are commented out. The captcha is still generated and written to
the session, but it is never read or checked during login ("generate only, never
verify"):
public Object login(@RequestBody String body, HttpServletRequest request) {
String username = JacksonUtil.parseString(body, "username");
String password = JacksonUtil.parseString(body, "password");
// String code = JacksonUtil.parseString(body, "code");
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
return ResponseUtil.badArgument();
}
// if (StringUtils.isEmpty(code)) {
// return ResponseUtil.fail(ADMIN_INVALID_KAPTCHA_REQUIRED, "验证码不能为空");
// }
//
// HttpSession session = request.getSession();
// String kaptcha = (String)session.getAttribute("kaptcha");
// if (Objects.requireNonNull(code).compareToIgnoreCase(kaptcha) != 0) {
// return ResponseUtil.fail(ADMIN_INVALID_KAPTCHA, "验证码不正确", doKaptcha(request));
// }
Subject currentUser = SecurityUtils.getSubject();
try {
currentUser.login(new UsernamePasswordToken(username, password));
} ...
}
Note: the frontend was changed consistently — in
litemall-admin/src/views/login/index.vue the captcha form item is also wrapped
in an HTML comment, and loginRules contains only username / password.
So this is not a frontend/backend inconsistency; the captcha feature has been
disabled on both ends. The security consequence is what matters here: there is no
human-interaction barrier left on the login endpoint.
2. No failure lockout
AdminAuthorizingRealm.doGetAuthenticationInfo(...) only throws
UnknownAccountException on a bad password. There is no failed-attempt counter,
no lockout, and no RetryLimit/HashedCredentialsMatcher configuration in the
Shiro chain.
3. No rate limiting
Neither the endpoint nor the Shiro filter chain applies any IP- or account-level
rate limiting.
4. Default seed credentials (impact amplifier)
litemall-db/sql/litemall_data.sql ships default admin accounts:
admin123 / admin123
mall123 / mall123
promotion123 / promotion123
Steps to Reproduce
All tests were performed against a local instance (http://localhost:8080/litemall).
A. Login without sending code (10 attempts)
for i in $(seq 1 10); do
curl -s -X POST http://localhost:8080/litemall/admin/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin123","password":"admin123"}'
echo
done
Result: 10/10 returned "errno":0 (success).
B. Login with a fixed wrong code (10 attempts)
for i in $(seq 1 10); do
curl -s -X POST http://localhost:8080/litemall/admin/auth/login
-H 'Content-Type: application/json'
-d '{"username":"admin123","password":"admin123","code":"WRONG123"}'
echo
done
Result: 10/10 returned "errno":0 (success). If the captcha were enforced,
a dedicated error code would be returned instead.
C. Cross-check — response depends only on password, not on code
| correct password + empty code |
errno:0 |
| correct password + wrong code |
errno:0 |
| wrong password + empty code |
errno:605 |
| wrong password + wrong code |
errno:605 |
The response code varies only with the password, never with code.
D. Brute-force feasibility (no lockout)###
# 10 attempts with wrong passwords, then the 11th with the correct one
Result: all 10 wrong attempts returned errno:605, no lockout occurred, and the
11th request with the correct password returned errno:0 — the account was
never locked.
Impact
- Administrator credentials can be brute-forced online without any delay,
captcha, or lockout constraint.
- Once a valid admin session is obtained, the attacker can reach other admin
endpoints, e.g.:
- SQL injection in
/admin/order/list (nickname/consignee/orderSn);
- Arbitrary file deletion in
/admin/storage/delete (executed with root
privileges).
- With the shipped default credentials, no brute-force is even required — the
accounts are directly accessible.
Root Cause
The login endpoint has the captcha verification removed, and there is no
failed-authentication rate limiting or account lockout mechanism.
Suggested Fix
- Restore the captcha verification in
AdminAuthController.login(...) and
re-enable the corresponding field in the frontend login form.
- Add failed-attempt counting + account lockout, or IP-level rate limiting
(e.g. Shiro HashedCredentialsMatcher with a retry limit, or a servlet
filter / gateway limiter).
- Force a password change on first login for the seed accounts, and remove the
hardcoded default credentials from the shipped SQL.
Summary
The
/admin/auth/loginendpoint provides no anti-automation protection: thecaptcha verification has been removed (commented out), repeated failures do not
trigger any account lockout, and there is no IP/account-level rate limiting.
An attacker can therefore perform unlimited online brute-force attacks against
administrator credentials and eventually take over the admin backend.
litemall-admin-apiAffected Endpoint
POST /admin/auth/login
Source file:
Details
1. Captcha verification is commented out
In
AdminAuthController.login(...), both the parsing and the comparison of thecodefield are commented out. The captcha is still generated and written tothe session, but it is never read or checked during login ("generate only, never
verify"):
Note: the frontend was changed consistently — in
litemall-admin/src/views/login/index.vuethe captcha form item is also wrappedin an HTML comment, and
loginRulescontains onlyusername/password.So this is not a frontend/backend inconsistency; the captcha feature has been
disabled on both ends. The security consequence is what matters here: there is no
human-interaction barrier left on the login endpoint.
2. No failure lockout
AdminAuthorizingRealm.doGetAuthenticationInfo(...)only throwsUnknownAccountExceptionon a bad password. There is no failed-attempt counter,no lockout, and no
RetryLimit/HashedCredentialsMatcherconfiguration in theShiro chain.
3. No rate limiting
Neither the endpoint nor the Shiro filter chain applies any IP- or account-level
rate limiting.
4. Default seed credentials (impact amplifier)
litemall-db/sql/litemall_data.sqlships default admin accounts:Steps to Reproduce
All tests were performed against a local instance (
http://localhost:8080/litemall).A. Login without sending
code(10 attempts)Result: 10/10 returned
"errno":0(success).B. Login with a fixed wrong
code(10 attempts)for i in $(seq 1 10); do
curl -s -X POST http://localhost:8080/litemall/admin/auth/login
-H 'Content-Type: application/json'
-d '{"username":"admin123","password":"admin123","code":"WRONG123"}'
echo
done
Result: 10/10 returned
"errno":0(success). If the captcha were enforced,a dedicated error code would be returned instead.
C. Cross-check — response depends only on password, not on
codeThe response code varies only with the password, never with
code.D. Brute-force feasibility (no lockout)###
# 10 attempts with wrong passwords, then the 11th with the correct oneResult: all 10 wrong attempts returned
errno:605, no lockout occurred, and the11th request with the correct password returned
errno:0— the account wasnever locked.
Impact
captcha, or lockout constraint.
endpoints, e.g.:
/admin/order/list(nickname/consignee/orderSn);/admin/storage/delete(executed with rootprivileges).
accounts are directly accessible.
Root Cause
The login endpoint has the captcha verification removed, and there is no
failed-authentication rate limiting or account lockout mechanism.
Suggested Fix
AdminAuthController.login(...)andre-enable the corresponding field in the frontend login form.
(e.g. Shiro
HashedCredentialsMatcherwith a retry limit, or a servletfilter / gateway limiter).
hardcoded default credentials from the shipped SQL.