-
Notifications
You must be signed in to change notification settings - Fork 122
Handle scope field as string or array in DynamicClientRegistrationResponse #2083
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2083 +/- ##
==========================================
+ Coverage 48.27% 48.37% +0.10%
==========================================
Files 238 238
Lines 30006 30034 +28
==========================================
+ Hits 14484 14529 +45
+ Misses 14423 14402 -21
- Partials 1099 1103 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
@claude please review this with a focus on security |
Claude finished @JAORMX's task —— View job Security Review
SummaryThe implementation is generally secure with good defensive practices, but there are several areas that need attention for security hardening and robustness. 🔴 Critical Issues1. Potential Denial of Service via Memory Exhaustion (pkg/auth/oauth/dynamic_registration.go:77) The *s = strings.Fields(str) // split by spaces Problem: A malicious authorization server could send a very long string with many spaces, causing Recommendation: Add a maximum scope count check: fields := strings.Fields(str)
const maxScopes = 100 // reasonable limit
if len(fields) > maxScopes {
return fmt.Errorf("too many scopes: %d (max %d)", len(fields), maxScopes)
}
*s = fields 2. Information Disclosure in Error Messages (pkg/auth/oauth/dynamic_registration.go:93) return fmt.Errorf("invalid scope format: %s", string(data)) Problem: This error message could leak the raw JSON data received from the authorization server, which might contain sensitive information or be excessively long. This could be logged or exposed to users. Recommendation: Limit the error message length: maxLen := 100
dataStr := string(data)
if len(dataStr) > maxLen {
dataStr = dataStr[:maxLen] + "... (truncated)"
}
return fmt.Errorf("invalid scope format: %s", dataStr) 🟡 Medium Severity Issues3. Missing Scope Validation (pkg/auth/oauth/dynamic_registration.go:62-93) The
Problem: Invalid characters in scopes (spaces, control characters, quotes, etc.) are not detected, which could cause issues downstream or potentially be exploited for injection attacks if scopes are used in logging, SQL queries, or shell commands elsewhere in the codebase. Recommendation: Add scope validation: func isValidScope(s string) bool {
if s == "" {
return false
}
for _, r := range s {
// RFC 6749: %x21 / %x23-5B / %x5D-7E
if r < 0x21 || r == 0x22 || r == 0x5C || r > 0x7E {
return false
}
}
return true
}
// In UnmarshalJSON:
for _, v := range arr {
v = strings.TrimSpace(v)
if v == "" {
continue
}
if !isValidScope(v) {
return fmt.Errorf("invalid scope value")
}
*s = append(*s, v)
} 4. Array Unmarshaling Can Bypass Trimming (pkg/auth/oauth/dynamic_registration.go:84-89) When unmarshaling from an array, the code trims each element but doesn't validate for empty strings before trimming: for _, v := range arr {
if v = strings.TrimSpace(v); v != "" {
*s = append(*s, v)
}
} Issue: This allows scopes like Recommendation: Consider logging a warning when empty/whitespace-only scopes are encountered, or return an error for strict validation. 🟢 Low Severity / Best Practices5. Missing Tests for Security-Critical Edge Cases The codecov report shows 0% coverage for the new Missing test cases:
6. Type Conversion Without Explicit Length Check (pkg/auth/oauth/dynamic_registration.go:64) if string(data) == "null" { Minor Issue: Converting if len(data) == 4 && string(data) == "null" { 7. Inconsistent Null Handling (pkg/auth/oauth/dynamic_registration.go:64-66, 73-76) The code treats both
Consideration: Depending on OAuth server semantics, these might need different handling. RFC 7591 doesn't specify this clearly, so current behavior might be acceptable, but document this decision. ✅ Good Security Practices Observed
Recommendations SummaryMust Fix:
Should Fix: Nice to Have: Test Coverage Action ItemsAdd tests in func TestScopeList_UnmarshalJSON(t *testing.T) {
// Test cases for: string format, array format, null, empty string,
// whitespace handling, invalid formats, DoS attempts, etc.
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds a custom ScopeList type with a flexible JSON unmarshaler so DynamicClientRegistrationResponse.scope can accept either a space-delimited string or a JSON string array (plus null/empty handling).
- Introduces ScopeList with custom UnmarshalJSON supporting string, array, null, and empty input forms
- Replaces Scopes []string with Scopes ScopeList in DynamicClientRegistrationResponse
- Adds normalization logic (trimming, filtering empties)
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be improved later if necessary, but I suggest using assert
and require
from testify
to write tests.
Some authorization servers return the
scope
field as a space-delimitedstring (per RFC 7591), while others return it as a JSON array of strings.
This caused decoding errors when the format didn’t match expectations.
This change introduces a custom
ScopeList
type with a flexibleUnmarshalJSON implementation that correctly handles:
This ensures consistent behavior and provides a unified []string
representation in Go, regardless of how the server encodes scopes.