HIGH excessive data exposureecho go

Excessive Data Exposure in Echo Go

How Excessive Data Exposure Manifests in Echo Go

Excessive Data Exposure in Echo Go typically occurs when handlers return complete data structures without filtering sensitive fields. Echo Go's flexible context system and struct binding can inadvertently expose more data than intended.

A common pattern involves struct binding with ShouldBind or Bind where entire database models are passed directly to JSON responses:

type User struct {
    ID        int    `json:"id"`
    Email     string `json:"email"`
    Password  string `json:"password"`
    SSN       string `json:"ssn"`
    CreatedAt time.Time
}

func getUser(c echo.Context) error {
    user := User{ID: 123}
    return c.JSON(http.StatusOK, user) // Password and SSN exposed!
}

Echo Go's context binding makes this particularly dangerous. When using c.Bind(&user) with struct tags, developers might assume only tagged fields are exposed, but the actual JSON marshaling behavior depends on the struct's field visibility and tags:

type SensitiveResponse struct {
    UserID   int    `json:"user_id"`
    Token    string `json:"token"`
    Internal string // No JSON tag, but still exposed if exported
    password string // Unexported, won't be exposed
}

func sensitiveHandler(c echo.Context) error {
    resp := SensitiveResponse{
        UserID:   456,
        Token:    "jwt.token.here",
        Internal: "secret-data",
    }
    return c.JSON(http.StatusOK, resp)
}

Echo Go's middleware chain can also contribute to data exposure. If authentication middleware stores user objects in the context but subsequent handlers don't properly filter them:

func authMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
        user := findUserByToken(c.Request().Header.Get("Authorization"))
        c.Set("user", user) // Entire user object stored
        return next(c)
    }
}

func profileHandler(c echo.Context) error {
    user := c.Get("user").(User)
    return c.JSON(http.StatusOK, user) // All user fields exposed
}

Echo Go-Specific Detection

Detecting Excessive Data Exposure in Echo Go requires examining both the code structure and runtime behavior. middleBrick's black-box scanning can identify exposed sensitive data patterns without needing access to source code:

Code Analysis Patterns:

// Look for these patterns in Echo Go handlers
// 1. Direct struct returns without filtering
return c.JSON(http.StatusOK, model)

// 2. Context binding without field validation
c.Bind(&request)

// 3. Middleware storing sensitive objects
c.Set("sensitive", data)

// 4. Echo's default JSON serialization behavior
c.JSONPretty(...)

middleBrick Scanning: The scanner tests Echo Go endpoints by sending requests and analyzing responses for sensitive data patterns. It checks for:

  • API keys, tokens, and credentials in JSON responses
  • Database identifiers that could enable enumeration
  • Internal system information (file paths, stack traces)
  • Debug information exposed in development mode
  • Excessive pagination data with internal IDs

Runtime Detection: For Echo Go applications, you can add diagnostic middleware to log response sizes and field counts:

func auditMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
        start := time.Now()
        err := next(c)
        
        if err == nil {
            resp := c.Response()
            if resp.Size > 1024 { // Large responses warrant inspection
                log.Printf("Large response: %d bytes from %s", resp.Size, c.Request().URL)
            }
        }
        return err
    }
}

Echo Go-Specific Tools: Use Echo's built-in validation and filtering capabilities:

type UserResponse struct {
    ID        int    `json:"id"`
    Username  string `json:"username"`
    Email     string `json:"email"`
}

func safeHandler(c echo.Context) error {
    user := User{ID: 1, Email: "user@example.com", Password: "hashed"}
    resp := UserResponse{
        ID:       user.ID,
        Username: strings.Split(user.Email, "@")[0],
        Email:    user.Email,
    }
    return c.JSON(http.StatusOK, resp)
}

Echo Go-Specific Remediation

Remediating Excessive Data Exposure in Echo Go requires implementing strict data filtering and using Echo's built-in response control features. The key principle is never returning entire structs or database models directly.

Response Structs: Create dedicated response types that explicitly define what data is exposed:

type UserProfile struct {
    ID        int    `json:"id"`
    Username  string `json:"username"`
    Email     string `json:"email"`
    CreatedAt string `json:"created_at"`
}

type OrderSummary struct {
    OrderID     int    `json:"order_id"`
    TotalAmount string `json:"total_amount"`
    Status      string `json:"status"`
}

func getUserProfile(c echo.Context) error {
    userID := c.Param("id")
    user, err := db.GetUser(userID)
    if err != nil {
        return echo.NewHTTPError(http.StatusNotFound, "User not found")
    }
    
    response := UserProfile{
        ID:        user.ID,
        Username:  user.Username,
        Email:     user.Email,
        CreatedAt: user.CreatedAt.Format(time.RFC3339),
    }
    return c.JSON(http.StatusOK, response)
}

Echo Go's JSON Control: Use Echo's response writer to control exactly what gets serialized:

func filteredResponse(c echo.Context, data interface{}, allowedFields []string) error {
    // Convert to map and filter
    var filtered map[string]interface{}
    
    switch v := data.(type) {
    case map[string]interface{}:
        filtered = make(map[string]interface{})
        for _, field := range allowedFields {
            if val, exists := v[field]; exists {
                filtered[field] = val
            }
        }
    default:
        // For structs, use reflection to filter
        filtered = filterStructFields(v, allowedFields)
    }
    
    return c.JSON(http.StatusOK, filtered)
}

func filterStructFields(data interface{}, allowed []string) map[string]interface{} {
    val := reflect.ValueOf(data)
    if val.Kind() == reflect.Ptr {
        val = val.Elem()
    }
    
    typ := val.Type()
    result := make(map[string]interface{})
    
    for _, field := range allowed {
        f := val.FieldByName(field)
        if f.IsValid() {
            result[field] = f.Interface()
        }
    }
    return result
}

Middleware-Based Filtering: Create reusable middleware that automatically filters sensitive data:

type FilterConfig struct {
    AllowedFields []string
}

func filterResponse(config FilterConfig) echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return func(c echo.Context) error {
            err := next(c)
            if err != nil {
                return err
            }
            
            // Get the response data (requires response recorder)
            recorder := &responseRecorder{ResponseWriter: c.Response().Writer, body: &bytes.Buffer{}}
            c.Response().Writer = recorder
            
            // Continue processing
            err = next(c)
            if err != nil {
                return err
            }
            
            // Filter the response
            var data map[string]interface{}
            json.Unmarshal(recorder.body.Bytes(), &data)
            
            filtered := make(map[string]interface{})
            for _, field := range config.AllowedFields {
                if val, exists := data[field]; exists {
                    filtered[field] = val
                }
            }
            
            return c.JSON(http.StatusOK, filtered)
        }
    }
}

Related CWEs: propertyAuthorization

CWE IDNameSeverity
CWE-915Mass Assignment HIGH

Frequently Asked Questions

How does middleBrick detect Excessive Data Exposure in Echo Go applications?
middleBrick performs black-box scanning by sending requests to Echo Go endpoints and analyzing the JSON responses. It looks for patterns like API keys, tokens, database IDs, and internal system information that shouldn't be exposed. The scanner tests unauthenticated endpoints and checks if sensitive data is returned without proper authorization checks.
Can Echo Go's JSON serialization be configured to prevent data exposure?
Yes, Echo Go uses Go's standard JSON marshaling, so you can use struct tags like `json:"-"` to omit fields, create dedicated response structs, or implement the `MarshalJSON()` method for custom serialization. The key is never returning entire database models directly to clients.