Skip to content
Merged
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
43 changes: 33 additions & 10 deletions internal/probe/mcp/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,16 @@ func (p *redirectUriLaxityProbe) Run(ctx context.Context, s probe.Session, r *re
return nil
}

const maxRedirectURIDepth = 10

func findRedirectURIs(value any) []string {
return findRedirectURIsAt(value, 0)
}

func findRedirectURIsAt(value any, depth int) []string {
if depth > maxRedirectURIDepth {
return nil
}
out := []string{}
switch v := value.(type) {
case map[string]any:
Expand All @@ -437,11 +446,11 @@ func findRedirectURIs(value any) []string {
}
}
}
out = append(out, findRedirectURIs(child)...)
out = append(out, findRedirectURIsAt(child, depth+1)...)
}
case []any:
for _, item := range v {
out = append(out, findRedirectURIs(item)...)
out = append(out, findRedirectURIsAt(item, depth+1)...)
}
}
return out
Expand All @@ -455,16 +464,30 @@ func isBroadRedirectURI(target string) bool {
if err != nil {
return true
}
if parsed.Scheme != "https" {
return true
}
if parsed.Host == "" {
return true
}
if parsed.Path == "" || parsed.Path == "/" {
switch parsed.Scheme {
case "https":
// Require a non-empty host and a path deeper than "/".
return parsed.Host == "" || parsed.Path == "" || parsed.Path == "/"
case "http":
// RFC 8252 §8.3 permits http://localhost (and 127.0.0.1/::1) for
// loopback redirect URIs in native apps. Flag everything else.
h := parsed.Hostname()
if h == "localhost" || h == "127.0.0.1" || h == "::1" {
return false
}
return true
default:
// javascript:, data:, vbscript: are code-injection vectors, not
// redirect URIs — flag them regardless of what the rest looks like.
switch parsed.Scheme {
case "javascript", "data", "vbscript":
return true
}
// Any other scheme (myapp://callback, urn:ietf:...) is a native-app
// custom URI scheme, which RFC 8252 explicitly allows. Empty scheme
// means a relative or malformed URI — flag it.
return parsed.Scheme == ""
}
return false
}

// --- session-id-entropy -------------------------------------------------
Expand Down