Skip to content

Commit 701c83a

Browse files
Merge pull request #4457 from Jabejixo/fix/hide-internal-500-error-details
fix: hide internal server error details from users
2 parents d1b2722 + b0a6ee9 commit 701c83a

File tree

7 files changed

+378
-19
lines changed

7 files changed

+378
-19
lines changed

server/deviceflowhandlers.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
"strings"
1212
"time"
1313

14-
"golang.org/x/net/html"
15-
1614
"github.com/dexidp/dex/storage"
1715
)
1816

@@ -300,9 +298,11 @@ func (s *Server) handleDeviceCallback(w http.ResponseWriter, r *http.Request) {
300298

301299
// Authorization redirect callback from OAuth2 auth flow.
302300
if errMsg := r.FormValue("error"); errMsg != "" {
303-
// escape the message to prevent cross-site scripting
304-
msg := html.EscapeString(errMsg + ": " + r.FormValue("error_description"))
305-
http.Error(w, msg, http.StatusBadRequest)
301+
// Log the error details but don't expose them to the user
302+
s.logger.ErrorContext(r.Context(), "OAuth2 authorization error",
303+
"error", errMsg,
304+
"error_description", r.FormValue("error_description"))
305+
s.renderError(r, w, http.StatusBadRequest, "Authorization failed. Please try again.")
306306
return
307307
}
308308

@@ -392,7 +392,8 @@ func (s *Server) handleDeviceCallback(w http.ResponseWriter, r *http.Request) {
392392
}
393393

394394
default:
395-
http.Error(w, fmt.Sprintf("method not implemented: %s", r.Method), http.StatusBadRequest)
395+
s.logger.ErrorContext(r.Context(), "unsupported method in device callback", "method", r.Method)
396+
s.renderError(r, w, http.StatusBadRequest, ErrMsgMethodNotAllowed)
396397
return
397398
}
398399
}

server/deviceflowhandlers_test.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,9 @@ func TestDeviceCallback(t *testing.T) {
222222
code: "somecode",
223223
error: "Error Condition",
224224
},
225-
expectedResponseCode: http.StatusBadRequest,
226-
expectedServerResponse: "Error Condition: \n",
225+
expectedResponseCode: http.StatusBadRequest,
226+
// Note: Error details should NOT be displayed to user anymore.
227+
// Instead, a safe generic message is shown.
227228
},
228229
{
229230
testName: "Expired Auth Code",
@@ -352,8 +353,9 @@ func TestDeviceCallback(t *testing.T) {
352353
code: "somecode",
353354
error: "<script>console.log(window);</script>",
354355
},
355-
expectedResponseCode: http.StatusBadRequest,
356-
expectedServerResponse: "&lt;script&gt;console.log(window);&lt;/script&gt;: \n",
356+
expectedResponseCode: http.StatusBadRequest,
357+
// Note: XSS data should NOT be displayed to user anymore.
358+
// Instead, a safe generic message is shown.
357359
},
358360
}
359361
for _, tc := range tests {
@@ -413,6 +415,29 @@ func TestDeviceCallback(t *testing.T) {
413415
t.Errorf("%s: Unexpected Response. Expected %q got %q", tc.testName, tc.expectedServerResponse, result)
414416
}
415417
}
418+
419+
// Special check for error message safety tests
420+
if tc.testName == "Prevent cross-site scripting" || tc.testName == "Error During Authorization" {
421+
result, _ := io.ReadAll(rr.Body)
422+
responseBody := string(result)
423+
424+
// Error details should NOT be present in the response (for security)
425+
if tc.testName == "Prevent cross-site scripting" {
426+
if strings.Contains(responseBody, "<script>") || strings.Contains(responseBody, "console.log(window)") {
427+
t.Errorf("%s: XSS script found in response, but should be blocked: %q", tc.testName, responseBody)
428+
}
429+
}
430+
if tc.testName == "Error During Authorization" {
431+
if strings.Contains(responseBody, "Error Condition") {
432+
t.Errorf("%s: Error details found in response, but should be hidden: %q", tc.testName, responseBody)
433+
}
434+
}
435+
436+
// Safe message should be present
437+
if !strings.Contains(responseBody, "Authorization failed. Please try again.") {
438+
t.Errorf("%s: Safe error message not found in response: %q", tc.testName, responseBody)
439+
}
440+
}
416441
})
417442
}
418443
}

server/errors.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package server
2+
3+
// Safe error messages for user-facing responses.
4+
// These messages are intentionally generic to avoid leaking internal details.
5+
// All actual error details should be logged server-side.
6+
7+
const (
8+
// ErrMsgLoginError is a generic login error message shown to users.
9+
// Used when authentication fails due to internal server errors.
10+
ErrMsgLoginError = "Login error. Please contact your administrator or try again later."
11+
12+
// ErrMsgAuthenticationFailed is shown when callback/SAML authentication fails.
13+
ErrMsgAuthenticationFailed = "Authentication failed. Please contact your administrator or try again later."
14+
15+
// ErrMsgInternalServerError is a generic internal server error message.
16+
ErrMsgInternalServerError = "Internal server error. Please contact your administrator or try again later."
17+
18+
// ErrMsgDatabaseError is shown when database operations fail.
19+
ErrMsgDatabaseError = "A database error occurred. Please try again later."
20+
21+
// ErrMsgInvalidRequest is shown when request parsing fails.
22+
ErrMsgInvalidRequest = "Invalid request. Please try again."
23+
24+
// ErrMsgMethodNotAllowed is shown when an unsupported HTTP method is used.
25+
ErrMsgMethodNotAllowed = "Method not allowed."
26+
)

0 commit comments

Comments
 (0)