Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions csrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,16 @@ func (cs *csrf) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// if we have an Origin header, check it against our allowlist
origin := r.Header.Get("Origin")
if origin != "" {
// RFC 6454 §7.3: privacy-sensitive contexts (sandboxed iframes,
// some redirects, data: URLs) send the literal string "null".
// That's an opaque origin, never the same as ours and never
// something we'd put on the trusted list, so reject it up front
// instead of leaning on url.Parse returning a host-less URL.
if origin == "null" {
r = envError(r, ErrBadOrigin)
cs.opts.ErrorHandler.ServeHTTP(w, r)
return
}
parsedOrigin, err := url.Parse(origin)
if err != nil {
r = envError(r, ErrBadOrigin)
Expand Down
8 changes: 8 additions & 0 deletions csrf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ func TestProtectScenarios(t *testing.T) {
originUntrusted bool
originHTTP bool
originTrusted bool
originNull bool
secureRequest bool
refererTrusted bool
refererUntrusted bool
Expand Down Expand Up @@ -456,6 +457,11 @@ func TestProtectScenarios(t *testing.T) {
refererRelative: true,
tokenInvalid: true,
},
{
name: `cleartext POST with Origin "null" reject`,
originNull: true,
tokenValid: true,
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -489,6 +495,8 @@ func TestProtectScenarios(t *testing.T) {
r.Header.Set("Origin", "https://www.gorillatoolkit.org")
case tt.originHTTP:
r.Header.Set("Origin", "http://www.gorillatoolkit.org")
case tt.originNull:
r.Header.Set("Origin", "null")
}

// Set the Referer header
Expand Down
Loading