Refuse a proxied path that does not start with a slash (#2638)

In absolute-form the path follows the authority, so a path such as "@evil.example/x" made the proxy connect to another host and forward the origin's credentials. Both handle_request and open_stream_ now refuse such a path before anything is written.
This commit is contained in:
metsw24-max authored and GitHub committed 2026-10-22 17:01:58 -04:00
1 parent b4b24589ad
commit 276cf08e84
2 files changed
+42 -2

No files matched your search

+30
View File
@@ -30415,6 +30415,36 @@ TEST(StreamRequestHeadTest, GoesThroughAPlainHttpProxy) {
EXPECT_EQ("Basic cHVzZXI6cHBhc3M=", proxy_authz);
}
// In absolute-form the path follows the authority, so a path that does not
// begin with '/' would make the proxy connect to another host
TEST(ProxyAbsoluteFormTest, PathMustNotExtendTheAuthority) {
std::vector<std::string> targets;
no_proxy_test::ScopedServer proxy;
proxy.svr().Get(".*", [&](const Request &req, Response &res) {
targets.push_back(req.target);
res.set_content("ok", "text/plain");
});
proxy.listen();
Client cli("origin.example", 8080);
cli.set_proxy("127.0.0.1", proxy.port());
cli.set_basic_auth("user", "pass");
for (const auto &path : {"@evil.example/x", ".evil.example/x", ":81/x"}) {
auto res = cli.Get(path);
EXPECT_FALSE(res) << path;
auto handle = cli.open_stream("GET", path);
EXPECT_FALSE(handle.is_valid()) << path;
}
EXPECT_TRUE(targets.empty());
auto res = cli.Get("/x");
ASSERT_TRUE(res);
ASSERT_EQ(1u, targets.size());
EXPECT_EQ("http://origin.example:8080/x", targets[0]);
}
TEST(NoProxyTest, ExactHostnameBypasses) {
ProxyAndTargetServers s;
auto cli = make_client("example.com", s);