Skip to content

Instantly share code, notes, and snippets.

@ALiwoto
Created May 30, 2025 06:30
Show Gist options
  • Save ALiwoto/b097f58e0edc2a6cb36702a1390d3856 to your computer and use it in GitHub Desktop.
Save ALiwoto/b097f58e0edc2a6cb36702a1390d3856 to your computer and use it in GitHub Desktop.
An example of CWE-424.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
)
// UserProfile represents a user's profile data
type UserProfile struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
IsAdmin bool `json:"is_admin"` // A potentially sensitive field
// This field is intentionally not exported in JSON by default for the main profile view.
// We'll see how an alternate path might expose it.
InternalNotes string `json:"-"`
}
// Mock database - in a real app, this would be a proper database.
var userProfiles = map[string]UserProfile{
"user123": {ID: "user123", Name: "Alice Wonderland", Email: "[email protected]", IsAdmin: false, InternalNotes: "VIP customer, handle with care."},
"user456": {ID: "user456", Name: "Bob The Admin", Email: "[email protected]", IsAdmin: true, InternalNotes: "System administrator account."},
"user789": {ID: "user789", Name: "Charlie User", Email: "[email protected]", IsAdmin: false, InternalNotes: "Regular user, last login: 2025-05-29."},
}
// --- Middleware (Simulated) ---
// In a real application, this would involve robust token validation, session checks, etc.
func checkAuth(r *http.Request) bool {
// Extremely simplified: Check for a specific API key in headers.
apiKey := r.Header.Get("X-API-Key")
if apiKey == "STRONG_SECRET_API_KEY" {
// Here you might also check user roles/permissions based on the API key.
// For this demo, any valid key grants access to the "protected" resource.
return true
}
return false
}
// --- HTTP Handlers ---
// 1. Primary, "Protected" Endpoint
// This endpoint is intended to be the official way to get user profiles and requires authentication.
func protectedUserProfileHandler(w http.ResponseWriter, r *http.Request) {
if !checkAuth(r) {
log.Printf("Auth failed for %s on /api/users/{id}", r.RemoteAddr)
http.Error(w, "Unauthorized: Missing or invalid API key.", http.StatusUnauthorized)
return
}
pathParts := strings.Split(r.URL.Path, "/") // e.g., ["", "api", "users", "user123"]
if len(pathParts) < 4 || pathParts[3] == "" {
http.Error(w, "User ID is missing in path.", http.StatusBadRequest)
return
}
userID := pathParts[3]
profile, exists := userProfiles[userID]
if !exists {
http.Error(w, "User not found.", http.StatusNotFound)
return
}
// For the protected endpoint, we might choose to return a limited view of the profile.
// (InternalNotes is omitted due to `json:"-"` in UserProfile struct)
log.Printf("Access granted to /api/users/%s for %s", userID, r.RemoteAddr)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(profile)
}
// 2. Vulnerable Alternate Path (CWE-424 Example 1: Debug Endpoint)
// This endpoint might have been created for debugging or internal use but was
// left exposed and without proper authentication/authorization checks.
func vulnerableDebugUserProfileHandler(w http.ResponseWriter, r *http.Request) {
pathParts := strings.Split(r.URL.Path, "/") // e.g., ["", "debug", "user-info", "user123"]
if len(pathParts) < 4 || pathParts[3] == "" {
http.Error(w, "User ID is missing in path for debug endpoint.", http.StatusBadRequest)
return
}
userID := pathParts[3]
// VULNERABILITY: No authentication or authorization check (checkAuth is NOT called).
// This alternate path bypasses the security of the primary endpoint.
profile, exists := userProfiles[userID]
if !exists {
http.Error(w, "User not found (via debug path).", http.StatusNotFound)
return
}
// To make it worse, this debug endpoint might expose more data than the primary one.
// For example, let's create a temporary struct to expose InternalNotes.
type DebugProfileView struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
IsAdmin bool `json:"is_admin"`
InternalNotes string `json:"internal_notes_exposed_by_debug"` // Explicitly exposing this
}
debugView := DebugProfileView{
ID: profile.ID,
Name: profile.Name,
Email: profile.Email,
IsAdmin: profile.IsAdmin,
InternalNotes: profile.InternalNotes, // Sensitive notes are now exposed
}
log.Printf("CWE-424 VULNERABILITY: Unauthenticated access to /debug/user-info/%s by %s (exposed sensitive notes)", userID, r.RemoteAddr)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(debugView)
}
// 3. Vulnerable Alternate Path (CWE-424 Example 2: Legacy or Forgotten Admin Endpoint)
// This endpoint might be an old admin function that was never properly secured or was forgotten.
func vulnerableLegacyAdminDumpHandler(w http.ResponseWriter, r *http.Request) {
// VULNERABILITY: No authentication check. This is an admin-level data dump.
// This path bypasses all security controls.
allProfiles := make([]UserProfile, 0, len(userProfiles))
for _, p := range userProfiles {
// To further demonstrate impact, let's say this path also exposes InternalNotes for all users.
// For simplicity, we'll just dump the existing structures, but InternalNotes is usually `json:"-"`.
// A real leak here might involve custom marshaling or a different struct that includes all fields.
// For this example, we'll focus on the lack of auth for an admin-like function.
// The `InternalNotes` will not be directly visible in this specific dump due to `json:"-"`.
// The main vulnerability here is unauthorized access to an admin-level data enumeration function.
allProfiles = append(allProfiles, p)
}
log.Printf("CWE-424 VULNERABILITY: Unauthenticated access to /internal-api/admin/dump-all-users by %s", r.RemoteAddr)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(allProfiles)
}
func main() {
// Primary, "secure" endpoint
http.HandleFunc("/api/users/", protectedUserProfileHandler)
// CWE-424: Vulnerable Alternate Paths
// These paths provide access to data or functionality without proper security controls.
http.HandleFunc("/debug/user-info/", vulnerableDebugUserProfileHandler) // Example 1: Debug path
http.HandleFunc("/internal-api/admin/dump-all-users", vulnerableLegacyAdminDumpHandler) // Example 2: Forgotten admin path
fmt.Println("Server starting on http://localhost:8080")
fmt.Println("---------------------------------------------------------------------")
fmt.Println("Endpoints:")
fmt.Println("1. Protected Profile API:")
fmt.Println(" GET http://localhost:8080/api/users/{userID}")
fmt.Println(" (Requires 'X-API-Key: STRONG_SECRET_API_KEY' header for auth)")
fmt.Println(" Example (Authenticated): curl -H \"X-API-Key: STRONG_SECRET_API_KEY\" http://localhost:8080/api/users/user123")
fmt.Println(" Example (Unauthenticated): curl http://localhost:8080/api/users/user123")
fmt.Println("\n2. CWE-424 Vulnerable Debug Path (exposes more data, no auth):")
fmt.Println(" GET http://localhost:8080/debug/user-info/{userID}")
fmt.Println(" Example: curl http://localhost:8080/debug/user-info/user123")
fmt.Println("\n3. CWE-424 Vulnerable Admin Dump Path (no auth):")
fmt.Println(" GET http://localhost:8080/internal-api/admin/dump-all-users")
fmt.Println(" Example: curl http://localhost:8080/internal-api/admin/dump-all-users")
fmt.Println("---------------------------------------------------------------------")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}

CWE-424

This type of vulnerability occurs when an application provides an alternative way to access resources or functionality that bypasses primary security controls.

This example illustrates how an improperly protected alternate path can undermine the security of an application, even if the primary paths are well-secured.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment