Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 86fbb0f

Browse files
committed
security: Validate redirects against security.http.urls
A server allowed by security.http.urls could redirect resources.GetRemote to a host that is not. Re-run the check on each hop via CheckRedirect. Fixes #14871
1 parent 7d4af7a commit 86fbb0f

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

resources/resource_factories/create/create.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package create
1717

1818
import (
19+
"errors"
1920
"net/http"
2021
"os"
2122
"path"
@@ -97,6 +98,15 @@ func New(rs *resources.Spec) *Client {
9798
remoteResourceLogger: rs.Logger.InfoCommand("remote"),
9899
httpClient: &http.Client{
99100
Timeout: httpTimeout,
101+
CheckRedirect: func(req *http.Request, via []*http.Request) error {
102+
if err := rs.ExecHelper.Sec().CheckAllowedHTTPURL(req.URL.String()); err != nil {
103+
return err
104+
}
105+
if len(via) >= 10 {
106+
return errors.New("stopped after 10 redirects")
107+
}
108+
return nil
109+
},
100110
Transport: &httpcache.Transport{
101111
Cache: fileCache.AsHTTPCache(),
102112
CacheKey: func(req *http.Request) string {

resources/resource_factories/create/create_integration_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,47 @@ urls = ['.*']
276276
})
277277
}
278278

279+
// Issue 14871.
280+
func TestGetRemoteRedirectSecurityCheckIssue14871(t *testing.T) {
281+
t.Parallel()
282+
283+
// Final server: the redirect target. Its host must be denied by security.http.urls.
284+
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
285+
w.Header().Add("Content-Type", "text/plain")
286+
w.Write([]byte("should not reach here"))
287+
}))
288+
t.Cleanup(func() { target.Close() })
289+
290+
// Redirector: the allowed host. Redirects to the denied target.
291+
redirector := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
292+
http.Redirect(w, r, target.URL+"/", http.StatusFound)
293+
}))
294+
t.Cleanup(func() { redirector.Close() })
295+
296+
files := `
297+
-- hugo.toml --
298+
[security]
299+
[security.http]
300+
urls = ['REDIRECTOR']
301+
mediaTypes = ['text/plain']
302+
-- layouts/home.html --
303+
{{ $url := "REDIRECTOR/" }}
304+
{{ with try (resources.GetRemote $url) }}
305+
{{ with .Err }}
306+
Err: {{ . }}
307+
{{ else with .Value }}
308+
Content: {{ .Content }}
309+
{{ end }}
310+
{{ end }}
311+
`
312+
files = strings.ReplaceAll(files, "REDIRECTOR", redirector.URL)
313+
314+
b := hugolib.Test(t, files)
315+
316+
b.AssertFileContent("public/index.html", "Err:", "security.http.urls")
317+
b.AssertFileContent("public/index.html", "! should not reach here")
318+
}
319+
279320
// Issue 14611.
280321
func TestGetRemotePerRequestTimeoutBodyRead(t *testing.T) {
281322
t.Parallel()

0 commit comments

Comments
 (0)