diff --git a/Libraries/LibWeb/SecureContexts/AbstractOperations.cpp b/Libraries/LibWeb/SecureContexts/AbstractOperations.cpp index 7ae8f18aa8..844cd5a8e3 100644 --- a/Libraries/LibWeb/SecureContexts/AbstractOperations.cpp +++ b/Libraries/LibWeb/SecureContexts/AbstractOperations.cpp @@ -33,7 +33,7 @@ Trustworthiness is_origin_potentially_trustworthy(URL::Origin const& origin) // 4. If origin’s host matches one of the CIDR notations 127.0.0.0/8 or ::1/128 [RFC4632], return "Potentially Trustworthy". if (origin.host().has()) { - if ((origin.host().get().to_u32() & 0xff000000) != 0) + if ((origin.host().get().to_u32() & 0xff000000) == 0x7f000000) return Trustworthiness::PotentiallyTrustworthy; } else if (origin.host().has()) { auto ipv6_address = origin.host().get(); diff --git a/Tests/LibWeb/CMakeLists.txt b/Tests/LibWeb/CMakeLists.txt index 7d4c8eafc2..91f14ed9c9 100644 --- a/Tests/LibWeb/CMakeLists.txt +++ b/Tests/LibWeb/CMakeLists.txt @@ -14,6 +14,7 @@ set(TEST_SOURCES TestMimeSniff.cpp TestNumbers.cpp TestRefCountedTreeNode.cpp + TestSecureContexts.cpp TestSourceHighlighter.cpp TestStrings.cpp ) @@ -27,6 +28,7 @@ ladybird_utility(css-tokenizer SOURCES css-tokenizer.cpp LIBS LibFileSystem LibM target_link_libraries(TestContentBlocker PRIVATE LibURL) target_link_libraries(TestControlMessageQueue PRIVATE LibSync) target_link_libraries(TestFetchURL PRIVATE LibURL) +target_link_libraries(TestSecureContexts PRIVATE LibURL) target_link_libraries(TestSourceHighlighter PRIVATE LibURL LibWebView) if (NOT WIN32) diff --git a/Tests/LibWeb/TestSecureContexts.cpp b/Tests/LibWeb/TestSecureContexts.cpp new file mode 100644 index 0000000000..a0adfd34d8 --- /dev/null +++ b/Tests/LibWeb/TestSecureContexts.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include +#include + +static bool is_potentially_trustworthy(StringView url_string) +{ + auto url = URL::Parser::basic_parse(url_string); + VERIFY(url.has_value()); + return Web::SecureContexts::is_url_potentially_trustworthy(*url) == Web::SecureContexts::Trustworthiness::PotentiallyTrustworthy; +} + +TEST_CASE(ipv4_loopback_is_potentially_trustworthy) +{ + EXPECT(is_potentially_trustworthy("http://127.0.0.1/"sv)); + // The whole 127.0.0.0/8 block is loopback, not just 127.0.0.1. + EXPECT(is_potentially_trustworthy("http://127.0.0.2/"sv)); + EXPECT(is_potentially_trustworthy("http://127.0.0.0/"sv)); + EXPECT(is_potentially_trustworthy("http://127.255.255.255/"sv)); +} + +TEST_CASE(non_loopback_ipv4_is_not_potentially_trustworthy) +{ + EXPECT(!is_potentially_trustworthy("http://8.8.8.8/"sv)); + EXPECT(!is_potentially_trustworthy("http://1.1.1.1/"sv)); + EXPECT(!is_potentially_trustworthy("http://192.168.1.1/"sv)); + // A non-zero final octet of 127 must not be mistaken for the leading octet. + EXPECT(!is_potentially_trustworthy("http://8.8.8.127/"sv)); + // Just outside 127.0.0.0/8 on either side. + EXPECT(!is_potentially_trustworthy("http://126.0.0.1/"sv)); + EXPECT(!is_potentially_trustworthy("http://128.0.0.1/"sv)); +} + +TEST_CASE(ipv6_loopback_is_potentially_trustworthy) +{ + EXPECT(is_potentially_trustworthy("http://[::1]/"sv)); + EXPECT(!is_potentially_trustworthy("http://[::2]/"sv)); +} + +TEST_CASE(localhost_is_potentially_trustworthy) +{ + EXPECT(is_potentially_trustworthy("http://localhost/"sv)); + EXPECT(is_potentially_trustworthy("http://foo.localhost/"sv)); + EXPECT(!is_potentially_trustworthy("http://example.com/"sv)); +} + +TEST_CASE(https_and_wss_are_potentially_trustworthy) +{ + EXPECT(is_potentially_trustworthy("https://example.com/"sv)); + EXPECT(is_potentially_trustworthy("wss://example.com/"sv)); + EXPECT(!is_potentially_trustworthy("http://example.com/"sv)); + EXPECT(!is_potentially_trustworthy("ws://example.com/"sv)); +}