Headline
CVE-2022-29188: Fix hostname parsing for square brackets · stripe/smokescreen@dea7b3c
Smokescreen is an HTTP proxy. The primary use case for Smokescreen is to prevent server-side request forgery (SSRF) attacks in which external attackers leverage the behavior of applications to connect to or scan internal infrastructure. Smokescreen also offers an option to deny access to additional (e.g., external) URLs by way of a deny list. There was an issue in Smokescreen that made it possible to bypass the deny list feature by surrounding the hostname with square brackets (e.g. [example.com]
). This only impacted the HTTP proxy functionality of Smokescreen. HTTPS requests were not impacted. Smokescreen version 0.0.4 contains a patch for this issue.
@@ -107,11 +107,11 @@ func TestClassifyAddr(t *testing.T) {
}
}
func TestUnsafeAllowPrivateRanges (t *testing.T) {
func TestUnsafeAllowPrivateRanges(t *testing.T) {
a := assert.New(t)
conf := NewConfig()
a.NoError(conf.SetDenyRanges([]string {"192.168.0.0/24", "10.0.0.0/8"}))
a.NoError(conf.SetDenyRanges([]string{"192.168.0.0/24", "10.0.0.0/8"}))
conf.ConnectTimeout = 10 * time.Second
conf.ExitTimeout = 10 * time.Second
conf.AdditionalErrorMessageOnDeny = “Proxy denied”
@@ -160,7 +160,6 @@ func TestUnsafeAllowPrivateRanges (t *testing.T) {
}
}
}
// TestClearsErrors tests that we are correctly preserving/removing the X-Smokescreen-Error header.
@@ -443,6 +442,52 @@ func TestInvalidHost(t *testing.T) {
}
}
var hostSquareBracketsCases = []struct {
scheme string
proxyType string
}{
{"http", "http"},
{"https", "connect"},
}
func TestHostSquareBrackets(t *testing.T) {
for _, testCase := range hostSquareBracketsCases {
t.Run(testCase.scheme, func(t *testing.T) {
a := assert.New(t)
r := require.New(t)
cfg, err := testConfig(“test-open-srv”)
require.NoError(t, err)
logHook := proxyLogHook(cfg)
proxySrv := proxyServer(cfg)
defer proxySrv.Close()
// Create a http.Client that uses our proxy
client, err := proxyClient(proxySrv.URL)
r.NoError(err)
resp, err := client.Get(fmt.Sprintf("%s://[stripe.com]", testCase.scheme))
if err != nil {
r.Contains(err.Error(), “Request rejected by proxy”)
} else {
r.Equal(http.StatusProxyAuthRequired, resp.StatusCode)
}
entry := findCanonicalProxyDecision(logHook.AllEntries())
r.NotNil(entry)
if a.Contains(entry.Data, “allow”) {
a.Equal(false, entry.Data[“allow”])
a.Equal("host matched rule in global deny list", entry.Data[“decision_reason”])
}
if a.Contains(entry.Data, “proxy_type”) {
a.Contains(entry.Data[“proxy_type”], testCase.proxyType)
}
})
}
}
func TestErrorHeader(t *testing.T) {
a := assert.New(t)
r := require.New(t)
Related news
### Impact The primary use case for Smokescreen is to prevent server-side request forgery (SSRF) attacks in which external attackers leverage the behavior of applications to connect to or scan internal infrastructure. Smokescreen also offers an option to deny access to additional (e.g., external) URLs by way of a deny list. There was an issue in Smokescreen that made it possible to bypass the deny list feature by surrounding the hostname with square brackets (e.g. `[example.com]`). ### Recommendation Upgrade Smokescreen to version 0.0.4 or later. ### Acknowledgements Thanks to [Axel Chong](https://github.com/haxatron) for reporting the issue. ### For more information Email us at [email protected]