Skip to content

Commit 2b3e11f

Browse files
author
Daniel Wolf
committed
Merge branch 'musicsnobj-feature/l33t-exploit'
* musicsnobj-feature/l33t-exploit: use optional third arg instead of env variable for max password length fuzzy match all py test versions update README w/ tested py versions, try 3.8.* as test version remove python 2 condition from mypy job add py versions 3.12 and 3.13 add py versions 3.9, 3.10, 3.11 trying another tox config tweak tox config rm reference to requirements.txt let tox control pytest version try python version 3.8.18 by itself update build.yml with python versions supported by Ubuntu 24.04 try dropping python versions older than 3.6 try v5 of setup-python gha add tox.ini, add python versions to test add max password length, default 72, configurable via ZXCVBN_MAX_LENGTH env var
2 parents 558084c + c7fc8b1 commit 2b3e11f

File tree

5 files changed

+44
-4
lines changed

5 files changed

+44
-4
lines changed

README.rst

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,18 @@ Output:
103103
}],
104104
}
105105

106+
Another optional argument is ``max_length``, allowing override of the default max password length of 72.
107+
.. code:: python
108+
109+
from zxcvbn import zxcvbn
110+
111+
results = zxcvbn('JohnSmith321', user_inputs=['John', 'Smith'], max_length=88)
112+
113+
.. warning::
114+
115+
We strongly advise against setting ``max_length`` greater than 72,
116+
as it can lead to long processing times and may leave server-side applications open
117+
to denial-of-service scenarios.
106118

107119
Custom Ranked Dictionaries
108120
--------------------------
@@ -121,18 +133,21 @@ In order to support more languages or just add password dictionaries of your own
121133
These lists will be added to the current ones, but you can also overwrite the current ones if you wish.
122134
The lists you add should be in order of how common the word is used with the most common words appearing first.
123135

136+
124137
CLI
125138
~~~
126139

127140
You an also use zxcvbn from the command line::
128141

129142
echo 'password' | zxcvbn --user-input <user-input> | jq
130143

144+
You can include a ``--max-length`` argument::
145+
echo '<long password>' | zxcvbn --max-length 142
146+
131147
You can also execute the zxcvbn module::
132148

133149
echo 'password' | python -m zxcvbn --user-input <user-input> | jq
134150

135-
136151
Contribute
137152
----------
138153

tests/l33t_exploit_test.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import pytest
2+
from zxcvbn import zxcvbn
3+
4+
# Test ACsploit-generated password targeting zxcvbn's l33t matching algorithm
5+
# (see https://github.com/GoSimpleLLC/nbvcxz/issues/60)
6+
def test_l33t_exploit():
7+
8+
password = "4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/4@8({[</369&#!1/|0$5+7%2/"
9+
10+
# Function should raise ValueError for input exceeding default max_length of 72 chars
11+
with pytest.raises(ValueError, match="Password exceeds max length of 72 characters"):
12+
zxcvbn(password, user_inputs=[None])

tests/zxcvbn_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# -*- coding: utf-8 -*-
2+
import pytest
23
from zxcvbn import zxcvbn
34

45

@@ -23,7 +24,7 @@ def test_long_password():
2324
input_ = None
2425
password = "weopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioejiojweopiopdsjmkldjvoisdjfioej"
2526

26-
zxcvbn(password, user_inputs=[input_])
27+
zxcvbn(password, user_inputs=[input_], max_length=316)
2728

2829

2930
def test_dictionary_password():

zxcvbn/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
import os
12
from datetime import datetime
23

34
from . import matching, scoring, time_estimates, feedback
45

5-
def zxcvbn(password, user_inputs=None):
6+
7+
def zxcvbn(password, user_inputs=None, max_length=72):
8+
# Throw error if password exceeds max length
9+
if len(password) > max_length:
10+
raise ValueError(f"Password exceeds max length of {max_length} characters.")
11+
612
try:
713
# Python 2 string types
814
basestring = (str, unicode)

zxcvbn/__main__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
help='user data to be added to the dictionaries that are tested against '
1717
'(name, birthdate, etc)',
1818
)
19+
parser.add_argument(
20+
'--max-length',
21+
default=72,
22+
type=int,
23+
help='Override password max length (default: 72)'
24+
)
1925

2026
class JSONEncoder(json.JSONEncoder):
2127
def default(self, o):
@@ -36,7 +42,7 @@ def cli():
3642
else:
3743
password = getpass.getpass()
3844

39-
res = zxcvbn(password, user_inputs=args.user_input)
45+
res = zxcvbn(password, user_inputs=args.user_input, max_length=args.max_length)
4046
json.dump(res, sys.stdout, indent=2, cls=JSONEncoder)
4147
sys.stdout.write('\n')
4248

0 commit comments

Comments
 (0)