Skip to content

feat(security): enforce password complexity policy (min length + common-password blocklist)#40670

Draft
rusackas wants to merge 1 commit into
masterfrom
feat/password-complexity-policy
Draft

feat(security): enforce password complexity policy (min length + common-password blocklist)#40670
rusackas wants to merge 1 commit into
masterfrom
feat/password-complexity-policy

Conversation

@rusackas
Copy link
Copy Markdown
Member

@rusackas rusackas commented Jun 2, 2026

Draft / hold:testing — enables a password policy by default (behavior change on password-setting flows). Needs end-to-end validation before merge.

SUMMARY

SupersetSecurityManager enforced no password policy, so DB-auth self-registration and password changes accepted trivially short or common passwords (FINDING-014 / 015 — ASVS 6.2.1, 6.2.4, CWE-521).

This adds superset.security.password_complexity.validate_password_complexity:

  • minimum length via AUTH_PASSWORD_MIN_LENGTH (default 8), and
  • a common-password blocklist (built-in set of the most common passwords; extendable via AUTH_PASSWORD_COMMON_BLOCKLIST).

It's wired through Flask-AppBuilder's FAB_PASSWORD_COMPLEXITY_ENABLED + FAB_PASSWORD_COMPLEXITY_VALIDATOR. FAB runs this callable from both the WTForms password fields (self-registration, user edit, reset password) and the User REST API — so a single function covers every password-setting flow, with clean validation errors. The policy is intentionally less draconian than FAB's built-in default_password_complexity (which requires 2 uppercase + 1 special + 2 digits + 3 lowercase + length 10).

WHY DRAFT (hold:testing)

Enabling the policy by default changes behavior: short/common passwords are now rejected at registration, password change, and API-driven user provisioning. Needs validation that the form flows and the User API surface the error cleanly and that no existing automated provisioning relies on weak passwords.

TESTING INSTRUCTIONS

pytest tests/unit_tests/security/test_password_complexity.py

Tests: strong password accepted; short rejected; common rejected (case-insensitive); configurable min length; extra blocklist honored.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration
  • Introduces new feature or API (config-driven policy)
  • Removes existing feature or API

🤖 Generated with Claude Code

SupersetSecurityManager did not enforce any password policy, so DB-auth
self-registration / password changes accepted trivially short or common
passwords (ASVS 6.2.1 / 6.2.4, CWE-521).

Add superset.security.password_complexity.validate_password_complexity (minimum
length via AUTH_PASSWORD_MIN_LENGTH, default 8, plus a common-password
blocklist extendable via AUTH_PASSWORD_COMMON_BLOCKLIST), and wire it through
Flask-AppBuilder's FAB_PASSWORD_COMPLEXITY_ENABLED / _VALIDATOR. FAB runs this
callable from both the WTForms password fields (self-registration, user edit,
reset password) and the User REST API, so one function covers all
password-setting flows. The policy is intentionally less draconian than FAB's
built-in default_password_complexity.

DRAFT: enabling the policy by default changes registration / password-change
behavior (short or common passwords are now rejected) and any API-driven user
provisioning that used weak passwords. Needs validation of the end-to-end flows
before merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rusackas rusackas added the hold:testing! On hold for testing label Jun 2, 2026
@netlify
Copy link
Copy Markdown

netlify Bot commented Jun 2, 2026

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 5efd69d
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a1e5643234f82000800bf62
😎 Deploy Preview https://deploy-preview-40670--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 2, 2026

Codecov Report

❌ Patch coverage is 63.15789% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.81%. Comparing base (a183582) to head (5efd69d).
⚠️ Report is 241 commits behind head on master.

Files with missing lines Patch % Lines
superset/security/password_complexity.py 50.00% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #40670      +/-   ##
==========================================
- Coverage   64.18%   63.81%   -0.38%     
==========================================
  Files        2591     2652      +61     
  Lines      138471   142172    +3701     
  Branches    32120    32568     +448     
==========================================
+ Hits        88883    90724    +1841     
- Misses      48056    49885    +1829     
- Partials     1532     1563      +31     
Flag Coverage Δ
hive 39.76% <63.15%> (+0.35%) ⬆️
mysql 58.40% <63.15%> (-0.66%) ⬇️
postgres 58.48% <63.15%> (-0.66%) ⬇️
presto 41.37% <63.15%> (+0.27%) ⬆️
python 59.96% <63.15%> (-0.61%) ⬇️
sqlite 58.13% <63.15%> (-0.64%) ⬇️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@rusackas rusackas requested a review from Copilot June 2, 2026 05:25
@rusackas rusackas requested review from dpgaspar and sha174n June 2, 2026 05:26
@rusackas rusackas moved this from Needs Review to Needs Follow-Up Work in Superset Review Help Wanted Jun 2, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Superset-specific password complexity policy (min length + common-password blocklist) and wires it into Flask-AppBuilder so it applies consistently across password-setting flows (registration, reset/change forms, and User REST API).

Changes:

  • Introduces superset.security.password_complexity.validate_password_complexity enforcing minimum length and rejecting common passwords (plus configurable extra blocklist).
  • Enables FAB password complexity enforcement by default and adds config knobs (AUTH_PASSWORD_MIN_LENGTH, AUTH_PASSWORD_COMMON_BLOCKLIST).
  • Adds unit tests covering acceptance/rejection cases and config overrides.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
superset/security/password_complexity.py New validator implementing the policy and producing localized validation errors.
superset/config.py Enables FAB password complexity by default and defines policy configuration defaults.
tests/unit_tests/security/test_password_complexity.py Unit tests for the validator behavior and config override handling.

Comment on lines +91 to +92
min_length = current_app.config.get("AUTH_PASSWORD_MIN_LENGTH", DEFAULT_MIN_LENGTH)
if len(password) < min_length:
Comment on lines +100 to +102
extra = current_app.config.get("AUTH_PASSWORD_COMMON_BLOCKLIST") or []
blocklist = COMMON_PASSWORDS | {str(item).lower() for item in extra}
if password.lower() in blocklist:
Comment thread superset/config.py
Comment on lines +347 to +359
# Password complexity policy, enforced (via Flask-AppBuilder) across
# self-registration, the user edit/reset forms, and the User REST API.
# The Superset validator requires a minimum length and rejects common
# passwords; tune via AUTH_PASSWORD_MIN_LENGTH / AUTH_PASSWORD_COMMON_BLOCKLIST,
# or replace FAB_PASSWORD_COMPLEXITY_VALIDATOR with your own callable.
from superset.security.password_complexity import ( # noqa: E402
validate_password_complexity as _validate_password_complexity,
)

FAB_PASSWORD_COMPLEXITY_ENABLED = True
FAB_PASSWORD_COMPLEXITY_VALIDATOR = _validate_password_complexity
AUTH_PASSWORD_MIN_LENGTH = 8
AUTH_PASSWORD_COMMON_BLOCKLIST: list[str] = []
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Needs Follow-Up Work

Development

Successfully merging this pull request may close these issues.

4 participants