Skip to content

Prevent reverse-proxy SSRF via @ in sub-path of authority-only target - #916

Draft
ithewei with Copilot wants to merge 2 commits into
masterfrom
copilot/fix-ssrf-vulnerability
Draft

ithewei with Copilot wants to merge 2 commits into
masterfrom
copilot/fix-ssrf-vulnerability

Conversation

Copilot AI commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

HttpService::GetProxyUrl() joins the configured backend URL and the stripped request path by plain string concatenation. If the backend has no path (e.g. Proxy("/api/", "http://127.0.0.1:18081")), a request like GET /api/@169.254.169.254:80/latest/meta-data/ produces ******169.254.169.254:80/.... HUrl::parse() reads the configured host as userinfo and the attacker-supplied one as the real host. connectProxy() only checks the host for forward proxies, so the reverse proxy fetches an arbitrary host and returns the response.

  • GetProxyUrl()
    • When the configured target has no path component and the remaining request path is non-empty and doesn't start with /, a / is inserted before appending it.
    • The @ now ends up in the path, not the authority:
service.Proxy("/api/", "http://127.0.0.1:18081");

// GET /api/@169.254.169.254:80/x
// before: ******169.254.169.254:80/x   (host = 169.254.169.254)
// after:  http://127.0.0.1:18081/@169.254.169.254:80/x  (host = 127.0.0.1)
  • Scope and limits
    • Targets that already have a path (http://host/v1/) are unchanged. An @ after the first / can't change the host.
    • I did not add the issue's second suggestion, which is to check the final host and port against the configured target in connectProxy(). The / insertion closes the reported vector on its own.
    • This change is not compiled or tested, and I added no regression test.

Co-authored-by: ithewei <26049660+ithewei@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix SSRF vulnerability in HttpService::GetProxyUrl method Prevent reverse-proxy SSRF via @ in sub-path of authority-only target Oct 28, 2026
Copilot AI requested a review from ithewei October 28, 2026 03:11
@ithewei
ithewei requested a balanced review from Copilot October 28, 2026 10:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Scheme-less proxy targets remain vulnerable to SSRF because an attacker-controlled path can determine the host selected by URL parsing.

1 open issue
What changed in this PR

This PR hardens libhv’s reverse-proxy URL construction against the authority-changing @ payload reported in #915.

Changes:

  • Inserts / before a nonempty, non-slash-prefixed request suffix when the configured backend has no path.
  • Preserves existing concatenation behavior for targets that already contain a path.
File Description
http/​server/​HttpService.cpp Adds an authority/path separator check in GetProxyUrl().

Review effort: Balanced

Comment on lines +202 to +203
size_t authority = url.find("://");
authority = authority == std::string::npos ? 0 : authority + 3;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security:HttpService::GetProxyUrl`反向代理 URL 纯字符串拼接未校验目标主机导致服务端请求伪造(SSRF)漏洞

3 participants