aboutsummaryrefslogtreecommitdiffstats
path: root/routes
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-27 07:53:38 -0700
committerAdam Soltys <[email protected]>2026-06-27 07:53:38 -0700
commitea23e9a5ba360ab77a16dfb8e48e5b2471fee8c4 (patch)
treec182be6d54b974ba9a406d7a404c310d811def0f /routes
parentd2762384156e3310ca08d7c295dea0e3856f8c9d (diff)
downloadcoinos-server-ea23e9a5ba360ab77a16dfb8e48e5b2471fee8c4.tar.gz
coinos-server-ea23e9a5ba360ab77a16dfb8e48e5b2471fee8c4.zip
users: return generic 404 from /reset for non-admins
The admin-only password-reset endpoint returned "disabled" to non-admin callers, which confirmed both that the endpoint exists and that it is admin-gated. Return a generic 404 identical to an unregistered route instead; still log the rejected attempt server-side for monitoring. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'routes')
-rw-r--r--routes/users.ts11
1 files changed, 10 insertions, 1 deletions
diff --git a/routes/users.ts b/routes/users.ts
index 3bf41355..572224be 100644
--- a/routes/users.ts
+++ b/routes/users.ts
@@ -759,7 +759,16 @@ export default {
let id;
let user;
- if (u.username !== config.admin) fail("disabled");
+ // Non-admins must not be able to tell this admin-only endpoint exists.
+ // Log the probe (so exploit-watch can flag it) but return a generic 404
+ // identical to an unregistered route — previously it returned "disabled",
+ // which confirmed the endpoint AND its admin-gating to attackers.
+ if (u?.username !== config.admin) {
+ err("password reset failed disabled", req.headers["cf-connecting-ip"]);
+ return res
+ .code(404)
+ .send({ message: "Route POST:/reset not found", error: "Not Found", statusCode: 404 });
+ }
id = await g(`user:${username.toLowerCase().replace(/\s/g, "")}`);
user = await g(`user:${id}`);