Related to
Web-Frontend (what users interact with)
Impact
security improvements
Missing Feature
Summary
Semaphore does not enforce any strength requirements on local (non-external) account passwords. A password of a single character can be set through the API. There is no configuration option to require a minimum length or any character-class complexity.
Current behavior
The web UI performs a client-side minimum-length check, but it is not enforced on the server, so it is bypassed by calling the API directly.
POST /api/users, PUT /api/users/{id}/ and POST /api/users/{id}/password accept a password of any length, including one character.
No config.json / environment option exists to set a policy.
Steps to reproduce
As an admin, call POST /api/users with a one-character password.
The user is created (HTTP 201); the weak password is accepted.
(Any Semaphore instance with a local admin account reproduces this; no special setup.)
Expected behavior
A configurable, server-side password policy applied to every path that sets a local password (API and CLI), so it cannot be bypassed by talking to the API directly. External (LDAP/OIDC) accounts, which carry no local password, are unaffected.
Proposed solution
Add an optional password_policy config block (and matching SEMAPHORE_PASSWORD_* environment variables):
"password_policy": {
"min_length": 12,
"require_uppercase": true,
"require_lowercase": true,
"require_number": true,
"require_symbol": true
}
Enforced centrally in the DB store layer (db/sql/user.go: CreateUser, UpdateUser, SetUserPassword) via a shared db.ValidatePassword, so the API and the CLI share one check. Validation failures return the existing validation-error type, surfaced by the API as HTTP 400 with a descriptive message.
Implementation
I have a working patch tested with local users, which I can share on a new PR if needed.
Design
No response
Related to
Web-Frontend (what users interact with)
Impact
security improvements
Missing Feature
Summary
Semaphore does not enforce any strength requirements on local (non-external) account passwords. A password of a single character can be set through the API. There is no configuration option to require a minimum length or any character-class complexity.
Current behavior
The web UI performs a client-side minimum-length check, but it is not enforced on the server, so it is bypassed by calling the API directly.
POST /api/users, PUT /api/users/{id}/ and POST /api/users/{id}/password accept a password of any length, including one character.
No config.json / environment option exists to set a policy.
Steps to reproduce
As an admin, call POST /api/users with a one-character password.
The user is created (HTTP 201); the weak password is accepted.
(Any Semaphore instance with a local admin account reproduces this; no special setup.)
Expected behavior
A configurable, server-side password policy applied to every path that sets a local password (API and CLI), so it cannot be bypassed by talking to the API directly. External (LDAP/OIDC) accounts, which carry no local password, are unaffected.
Proposed solution
Add an optional password_policy config block (and matching SEMAPHORE_PASSWORD_* environment variables):
"password_policy": {
"min_length": 12,
"require_uppercase": true,
"require_lowercase": true,
"require_number": true,
"require_symbol": true
}
Enforced centrally in the DB store layer (db/sql/user.go: CreateUser, UpdateUser, SetUserPassword) via a shared db.ValidatePassword, so the API and the CLI share one check. Validation failures return the existing validation-error type, surfaced by the API as HTTP 400 with a descriptive message.
Implementation
I have a working patch tested with local users, which I can share on a new PR if needed.
Design
No response