From 6ddbff39c7eb27e825616b479a6f3cd691184fd2 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Sun, 31 May 2026 19:09:20 +0100 Subject: [PATCH] LibWeb/SecureContexts: Correct the 127.0.0.0/8 trustworthiness check This previously checked whether the first octet was non-zero, treating most IPv4 addresses (e.g. 183.189.143.11) as potentially trustworthy. Match the first octet against 0x7f so only 127.0.0.0/8 is trusted. --- .../SecureContexts/AbstractOperations.cpp | 2 +- Tests/LibWeb/CMakeLists.txt | 2 + Tests/LibWeb/TestSecureContexts.cpp | 60 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 Tests/LibWeb/TestSecureContexts.cpp 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)); +}