Opened 62 minutes ago
Last modified 53 minutes ago
#37279 new Bug
URLValidator accepts null characters in URLs
| Reported by: | Nguyễn Anh Bình | Owned by: | |
|---|---|---|---|
| Component: | Core (Other) | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
URLValidator rejects tab and newline characters (via unsafe_chars = frozenset("\t\r\n"), added in #32713) but not the null character (\x00).
Example (Django 6.2.dev):
>>> from django.core.validators import URLValidator >>> URLValidator()("http://www.djangoproject.com/\x00") # no newline/tab, contains \x00 >>> URLValidator()("http://example.com/page\x00@example.com/")
Neither call raises ValidationError.
This is inconsistent with the rest of Django's input handling:
forms.CharField(and thereforeforms.URLField) rejects\x00viaProhibitNullCharactersValidator(#28201), so the same value submitted through a form is rejected.- Model-level
URLFieldonly appliesURLValidator(), so values that reachModel.full_clean()through non-form paths (data imports, management commands, direct ORM writes from other systems) validate successfully while the identical value would fail any Django form. ProhibitNullCharactersValidatorexists precisely because NUL cannot appear in a valid URL and causes failures in downstream components (e.g. most databases reject or truncate it; PostgreSQL raises "A string literal cannot contain NUL (0x00) characters").
Null characters are invalid in URLs per RFC 3986 (excluded from every grammar production, ASCII control characters must be percent-encoded).
Proposed fix, mirroring the #32713 approach:
--- a/django/core/validators.py +++ b/django/core/validators.py @@ class URLValidator(RegexValidator): - unsafe_chars = frozenset("\t\r\n") + unsafe_chars = frozenset("\t\r\n\x00")
Happy to submit a PR with tests.
(Initially reported to security@…; the team classified it as non-security since form-based flows already reject NUL, and suggested the public tracker for the consistency hardening.)
PR with the proposed fix and tests: https://github.com/django/django/pull/21787
(The PR was closed by the automation because this ticket is not yet Accepted; it will be re-submitted once the ticket is triaged.)