Skip to content

Add SSRF filter for HTTPX#23480

Merged
NobodysNightmare merged 1 commit into
devfrom
httpx-ssrf-filter
Jun 4, 2026
Merged

Add SSRF filter for HTTPX#23480
NobodysNightmare merged 1 commit into
devfrom
httpx-ssrf-filter

Conversation

@NobodysNightmare

@NobodysNightmare NobodysNightmare commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Filtering in front of HTTPX calls is less secure, because it's vulnerable to DNS rebinding. In addition to that it's also duplicate work, because all affected callsites would have to make sure to "remember" SSRF filtering.

This SSRF filter is inspired by the original HTTPX SSRF Filter, but using our custom IP address matcher that allows to configure safe IP addresses or ranges.

Ticket

none

Notes

I left the existing checks for safe_ip? where they are, because they tend to add more meaningful error messages to the corresponding form than leaving them out.

Without those the corresponding forms would be left alone with a request error from trying to run httpx.get, which ranges from "error message is now less helpful" to "error case wasn't considered at all so far".

It's worth noting that the HTTPX maintainer seems open to the idea of supporting additional requirements regarding SSRF directly in the gem. This PR here might be replaced with a native alternative, once one becomes available. See https://gitlab.com/os85/httpx/-/work_items/384

@NobodysNightmare NobodysNightmare force-pushed the httpx-ssrf-filter branch 2 times, most recently from da5859b to e34c8c9 Compare June 1, 2026 11:32

@ba1ash ba1ash left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM!

expect(response).to have_http_status(:not_found)
expect(Query.exists?(target_query.id)).to be(true)
it "does not filter requests to public IP addresses" do
result = httpx.get(public_endpoint)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@klaustopher FYI: Added some tests as requested. Sadly we can't properly test this through webmock, so I am making real requests here.

If this becomes a source of test flicker we'll have to do something about it (I don't yet know what).

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.

We can add another test, where we put 127.0.0.1 in the allowlist. This should be done with the with_setting helper, That's the difference to the base gem that we allow the allowlist

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Working on it. Even though neither with_settings nor with_config seem to do the trick. Little excerpt from with_config:

[1] pry(#<RSpec::ExampleGroups::OpenProject::Httpx::SSRFFiltering::WhenLocalIPAddressesAreAllowed>)> OpenProject::Configuration[:ssrf_protection_ip_allowlist]
=> "127.0.0.1,::1"
[2] pry(#<RSpec::ExampleGroups::OpenProject::Httpx::SSRFFiltering::WhenLocalIPAddressesAreAllowed>)> OpenProject::Configuration.ssrf_protection_ip_allowlist
=> []

So I am going to mock it like in spec/lib/open_project/ssrf_protection_spec.rb using allow(OpenProject::Configuration).to receive(:ssrf_protection_ip_allowlist)

Filtering in front of HTTPX calls is less secure, because it's vulnerable to
DNS rebinding. In addition to that it's also duplicate work, because all affected
callsites would have to make sure to "remember" SSRF filtering.

This SSRF filter is inspired by the original HTTPX SSRF Filter, but using our custom
IP address matcher that allows to configure safe IP addresses or ranges.
@NobodysNightmare NobodysNightmare merged commit 663dc3f into dev Jun 4, 2026
16 of 18 checks passed
@NobodysNightmare NobodysNightmare deleted the httpx-ssrf-filter branch June 4, 2026 05:19
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants