diff --git a/src/url_safety.py b/src/url_safety.py index ec7c8f8..cc68170 100644 --- a/src/url_safety.py +++ b/src/url_safety.py @@ -56,6 +56,8 @@ def check_outbound_url( Returns ``(ok, reason)``. ``ok`` is True only when the URL is safe to fetch. ``resolver`` is injectable so callers/tests can avoid real DNS. """ + if not isinstance(url, str): + return False, "URL must be a string" if not url or not url.strip(): return False, "URL is required" try: diff --git a/tests/test_check_outbound_url_nonstring.py b/tests/test_check_outbound_url_nonstring.py new file mode 100644 index 0000000..8c46215 --- /dev/null +++ b/tests/test_check_outbound_url_nonstring.py @@ -0,0 +1,14 @@ +"""Regression: check_outbound_url must reject a non-string URL, not crash. + +The `if not url or not url.strip()` guard only handled falsy values; a truthy +non-string (e.g. an int) reached `.strip()` and raised AttributeError out of +this SSRF check. Non-strings now fail closed with a clear message. +""" +from src.url_safety import check_outbound_url + + +def test_non_string_fails_closed(): + ok, _ = check_outbound_url(123) + assert ok is False + ok2, _ = check_outbound_url(None) + assert ok2 is False