From 02c1a621b1e64c1a91a86543bdff37f1ec8242a6 Mon Sep 17 00:00:00 2001 From: nandgator <38415384+nandgator@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:34:53 +0530 Subject: [PATCH 1/2] fix(slug): use fullmatch so a trailing newline is rejected --- src/validators/slug.py | 2 +- tests/test_slug.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/validators/slug.py b/src/validators/slug.py index 7fdc67ee..b15c97c8 100644 --- a/src/validators/slug.py +++ b/src/validators/slug.py @@ -29,4 +29,4 @@ def slug(value: str, /): (Literal[True]): If `value` is a valid slug. (ValidationError): If `value` is an invalid slug. """ - return _SLUG_REGEXP.match(value) is not None + return _SLUG_REGEXP.fullmatch(value) is not None diff --git a/tests/test_slug.py b/tests/test_slug.py index 5c62901c..45b59813 100644 --- a/tests/test_slug.py +++ b/tests/test_slug.py @@ -56,6 +56,9 @@ def test_returns_true_on_valid_slug(value: str): @pytest.mark.parametrize( "value", [ + # trailing newline must not be accepted ($ matches before a final \n) + "hello-world\n", + "\n", # with empty_string "", # with upper case From 918850fd7d14cbce38ec425081c0740589444a18 Mon Sep 17 00:00:00 2001 From: nandgator <38415384+nandgator@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:37:39 +0530 Subject: [PATCH 2/2] fix(uri): reject control characters in telnet URIs --- src/validators/uri.py | 7 ++++++- tests/test_uri.py | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/validators/uri.py b/src/validators/uri.py index 5b3b35f1..a3427494 100644 --- a/src/validators/uri.py +++ b/src/validators/uri.py @@ -28,7 +28,8 @@ def _ipfs_url(value: str): def _telnet_url(value: str): """Validate a telnet URL per RFC 4248. - Ref: https://www.rfc-editor.org/rfc/rfc4248" + Ref: https://www.rfc-editor.org/rfc/rfc4248 + Examples: >>> _telnet_url('telnet://example.com') True @@ -45,6 +46,10 @@ def _telnet_url(value: str): (Literal[True]): If `value` is a Telnet URI. (ValidationError): If `value` is an invalid URI. """ + # urlsplit silently strips tabs and newlines, so reject them up front + if any(char.isspace() or not char.isprintable() for char in value): + return False + try: scheme, netloc, path, query, fragment = urlsplit(value) except ValueError: diff --git a/tests/test_uri.py b/tests/test_uri.py index da5a8bb4..4feb2476 100644 --- a/tests/test_uri.py +++ b/tests/test_uri.py @@ -32,6 +32,10 @@ def test_valid_telnet_uri(value: str): "telnet://example.com/path", "telnet://example.com?query=1", "telnet://example.com#frag", + # urlsplit would silently strip these control characters + "telnet://example.com\n", + "telnet://exa\nmple.com", + "telnet://example.com\t", ], ) def test_invalid_telnet_uri(value: str):