Skip to content

fix(dashboard-auth): reject passwords longer than bcrypt's 72-byte limit#598

Merged
Soju06 merged 1 commit into
mainfrom
fix/password-bcrypt-72-byte-limit
May 13, 2026
Merged

fix(dashboard-auth): reject passwords longer than bcrypt's 72-byte limit#598
Soju06 merged 1 commit into
mainfrom
fix/password-bcrypt-72-byte-limit

Conversation

@Soju06
Copy link
Copy Markdown
Owner

@Soju06 Soju06 commented May 13, 2026

Fixes #597.

Root cause

bcrypt.hashpw enforces a hard 72-byte input limit on the encoded password (bcrypt 5.x raises ValueError("password cannot be longer than 72 bytes ...")). _hash_password in app/modules/dashboard_auth/service.py calls bcrypt.hashpw directly, and the two API entry points that lead there only validate len(password) < 8 before hashing.

So a password whose UTF-8 encoded length exceeds 72 bytes propagated as an unhandled ValueError and surfaced as a 500 with a generic "Unexpected error" on the dashboard frontend (the symptom reported in #597).

Fix

  • Add a shared _validate_password_length helper in app/modules/dashboard_auth/api.py that enforces both the existing 8-character minimum and a new 72-UTF-8-byte maximum.
  • Route both POST /api/dashboard-auth/password/setup and POST /api/dashboard-auth/password/change through it, so the two endpoints validate identically before hashing.
  • On the new failure case, return DashboardValidationError (HTTP 422) with code password_too_long and a message that references the 72-byte limit, so the dashboard can render a clear, actionable error.

The limit is measured against the UTF-8 encoded byte length, not codepoint count, so multi-byte characters (emoji, non-ASCII letters) count for as many bytes as bcrypt itself counts. This matches bcrypt's own ceiling exactly.

Why 72 bytes specifically

bcrypt (the underlying password hashing primitive used by all major language bindings) silently truncates input after 72 bytes when hashing on most platforms, but the Python bcrypt 5.x package explicitly rejects oversize inputs with ValueError instead of silently truncating. Anything that exceeds bcrypt's 72-byte ceiling cannot be hashed at all, so the right place to surface that is at the API layer, not as an unhandled ValueError.

Tests

Added four integration tests in tests/integration/test_dashboard_password_auth.py:

tests/integration/test_dashboard_password_auth.py::test_password_setup_rejects_overlong_password PASSED
tests/integration/test_dashboard_password_auth.py::test_password_setup_accepts_72_byte_password PASSED
tests/integration/test_dashboard_password_auth.py::test_password_setup_counts_utf8_bytes_not_codepoints PASSED
tests/integration/test_dashboard_password_auth.py::test_password_change_rejects_overlong_new_password PASSED

Verification on this branch:

uv run ruff check app/modules/dashboard_auth/api.py tests/integration/test_dashboard_password_auth.py     # clean
uv run ruff format --check app/modules/dashboard_auth/api.py tests/integration/test_dashboard_password_auth.py  # clean
uv run ty check app/modules/dashboard_auth/api.py tests/integration/test_dashboard_password_auth.py        # clean
uv run pytest tests/integration/test_dashboard_password_auth.py tests/unit/test_dashboard_auth_api.py tests/unit/test_dashboard_auth_password_service.py -q   # 16 passed
npx @fission-ai/openspec validate validate-password-length                                                 # change is valid

OpenSpec

Added an OpenSpec change folder openspec/changes/validate-password-length/ capturing the new requirement under the admin-auth capability (length is bounded by bcrypt's input limit, measured in UTF-8 bytes, applied to both setup and change).

Migration / Compatibility

  • No schema or runtime migration.
  • No change to bcrypt behavior or to how passwords are stored.
  • Existing valid passwords are unaffected; the new check matches bcrypt's existing ceiling, so any password that could already be set is still accepted.

Hotfix candidate for v1.17.1

This is a small, scoped fix on the dashboard-auth API surface with no runtime impact. It is a good candidate for the next patch release.

Fixes #597.

`bcrypt.hashpw` enforces a hard 72-byte input limit on the encoded
password (bcrypt 5.x raises `ValueError("password cannot be longer than
72 bytes ...")`). `_hash_password` calls `bcrypt.hashpw` directly, and
the `/password/setup` and `/password/change` endpoints only validate the
8-character minimum before hashing. So a password whose UTF-8 encoded
length exceeds 72 bytes (long ASCII strings, emoji-only strings, etc.)
propagated as an unhandled `ValueError` and surfaced as a 500 with a
generic "Unexpected error" on the dashboard frontend.

Add a shared `_validate_password_length` helper that enforces both the
existing 8-character minimum and a new 72-UTF-8-byte maximum, and route
both endpoints through it. Failures now return HTTP 422 with code
`password_too_long` and a message that references the limit, so the
dashboard can render a clear, actionable error instead of swallowing the
failure as 'Unexpected error'.

The limit is measured against the UTF-8 encoded byte length to match
bcrypt's own ceiling exactly (multi-byte characters like emoji count for
more than one byte). Regression coverage exercises 73-byte ASCII
rejection, exact 72-byte acceptance, emoji-only multi-byte rejection,
and the `/password/change` `new_password` path.
@Soju06
Copy link
Copy Markdown
Owner Author

Soju06 commented May 13, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Soju06 Soju06 merged commit d9b0493 into main May 13, 2026
18 checks passed
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.

Error 500 when setting password

1 participant