Skip to content

Commit f27c38a

Browse files
felixxmcarltongibson
authored andcommitted
[2.2.x] Fixed CVE-2021-33571 -- Prevented leading zeros in IPv4 addresses.
validate_ipv4_address() was affected only on Python < 3.9.5, see [1]. URLValidator() uses a regular expressions and it was affected on all Python versions. [1] https://bugs.python.org/issue36384
1 parent 053cc95 commit f27c38a

File tree

5 files changed

+60
-1
lines changed

5 files changed

+60
-1
lines changed

django/core/validators.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class URLValidator(RegexValidator):
7575
ul = '\u00a1-\uffff' # unicode letters range (must not be a raw string)
7676

7777
# IP patterns
78-
ipv4_re = r'(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}'
78+
ipv4_re = r'(?:0|25[0-5]|2[0-4]\d|1\d?\d?|[1-9]\d?)(?:\.(?:0|25[0-5]|2[0-4]\d|1\d?\d?|[1-9]\d?)){3}'
7979
ipv6_re = r'\[[0-9a-f:\.]+\]' # (simple regex, validated later)
8080

8181
# Host patterns
@@ -256,6 +256,18 @@ def validate_ipv4_address(value):
256256
ipaddress.IPv4Address(value)
257257
except ValueError:
258258
raise ValidationError(_('Enter a valid IPv4 address.'), code='invalid')
259+
else:
260+
# Leading zeros are forbidden to avoid ambiguity with the octal
261+
# notation. This restriction is included in Python 3.9.5+.
262+
# TODO: Remove when dropping support for PY39.
263+
if any(
264+
octet != '0' and octet[0] == '0'
265+
for octet in value.split('.')
266+
):
267+
raise ValidationError(
268+
_('Enter a valid IPv4 address.'),
269+
code='invalid',
270+
)
259271

260272

261273
def validate_ipv6_address(value):

docs/releases/2.2.24.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,16 @@ the existence but also the file contents would have been exposed.
1717

1818
As a mitigation, path sanitation is now applied and only files within the
1919
template root directories can be loaded.
20+
21+
CVE-2021-33571: Possible indeterminate SSRF, RFI, and LFI attacks since validators accepted leading zeros in IPv4 addresses
22+
===========================================================================================================================
23+
24+
:class:`~django.core.validators.URLValidator`,
25+
:func:`~django.core.validators.validate_ipv4_address`, and
26+
:func:`~django.core.validators.validate_ipv46_address` didn't prohibit leading
27+
zeros in octal literals. If you used such values you could suffer from
28+
indeterminate SSRF, RFI, and LFI attacks.
29+
30+
:func:`~django.core.validators.validate_ipv4_address` and
31+
:func:`~django.core.validators.validate_ipv46_address` validators were not
32+
affected on Python 3.9.5+.

tests/validators/invalid_urls.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ http://1.1.1.1.1
4646
http://123.123.123
4747
http://3628126748
4848
http://123
49+
http://000.000.000.000
50+
http://016.016.016.016
51+
http://192.168.000.001
52+
http://01.2.3.4
53+
http://01.2.3.4
54+
http://1.02.3.4
55+
http://1.2.03.4
56+
http://1.2.3.04
4957
http://.www.foo.bar/
5058
http://.www.foo.bar./
5159
http://[::1:2::3]:8080/

tests/validators/tests.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@
135135
(validate_ipv4_address, '1.1.1.1\n', ValidationError),
136136
(validate_ipv4_address, '٧.2٥.3٣.243', ValidationError),
137137

138+
# Leading zeros are forbidden to avoid ambiguity with the octal notation.
139+
(validate_ipv4_address, '000.000.000.000', ValidationError),
140+
(validate_ipv4_address, '016.016.016.016', ValidationError),
141+
(validate_ipv4_address, '192.168.000.001', ValidationError),
142+
(validate_ipv4_address, '01.2.3.4', ValidationError),
143+
(validate_ipv4_address, '01.2.3.4', ValidationError),
144+
(validate_ipv4_address, '1.02.3.4', ValidationError),
145+
(validate_ipv4_address, '1.2.03.4', ValidationError),
146+
(validate_ipv4_address, '1.2.3.04', ValidationError),
147+
138148
# validate_ipv6_address uses django.utils.ipv6, which
139149
# is tested in much greater detail in its own testcase
140150
(validate_ipv6_address, 'fe80::1', None),
@@ -160,6 +170,16 @@
160170
(validate_ipv46_address, '::zzz', ValidationError),
161171
(validate_ipv46_address, '12345::', ValidationError),
162172

173+
# Leading zeros are forbidden to avoid ambiguity with the octal notation.
174+
(validate_ipv46_address, '000.000.000.000', ValidationError),
175+
(validate_ipv46_address, '016.016.016.016', ValidationError),
176+
(validate_ipv46_address, '192.168.000.001', ValidationError),
177+
(validate_ipv46_address, '01.2.3.4', ValidationError),
178+
(validate_ipv46_address, '01.2.3.4', ValidationError),
179+
(validate_ipv46_address, '1.02.3.4', ValidationError),
180+
(validate_ipv46_address, '1.2.03.4', ValidationError),
181+
(validate_ipv46_address, '1.2.3.04', ValidationError),
182+
163183
(validate_comma_separated_integer_list, '1', None),
164184
(validate_comma_separated_integer_list, '12', None),
165185
(validate_comma_separated_integer_list, '1,2', None),

tests/validators/valid_urls.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ http://0.0.0.0/
6363
http://255.255.255.255
6464
http://224.0.0.0
6565
http://224.1.1.1
66+
http://111.112.113.114/
67+
http://88.88.88.88/
68+
http://11.12.13.14/
69+
http://10.20.30.40/
70+
http://1.2.3.4/
71+
http://127.0.01.09.home.lan
6672
http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com
6773
http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com
6874
http://example.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

0 commit comments

Comments
 (0)