Data Exposure in Echo Go
How Data Exposure Manifests in Echo Go
Data exposure in Echo Go typically occurs through improper handling of sensitive information in API responses. The most common pattern involves inadvertently returning database IDs, internal system identifiers, or user metadata that should remain confidential. For example, a typical Echo Go endpoint might expose MongoDB's ObjectId as a string in JSON responses:
type UserResponse struct {
ID string `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
}
func getUserHandler(c echo.Context) error {
id := c.Param("id")
user, err := db.GetUserByID(id)
if err != nil {
return c.JSON(http.StatusNotFound, map[string]string{"error": "User not found"})
}
return c.JSON(http.StatusOK, UserResponse{
ID: user.ID.Hex(),
Email: user.Email,
Username: user.Username,
})
}
This exposes the MongoDB ObjectId, which can be used for enumeration attacks. An attacker can increment the ID value to discover other users in the system. The ObjectId contains timestamp information and can reveal when accounts were created.
Another common Echo Go data exposure pattern involves returning stack traces or error details in production:
func createPostHandler(c echo.Context) error {
var post Post
if err := c.Bind(&post); err != nil {
return c.JSON(http.StatusBadRequest, map[string]interface{}{
"error": err.Error(),
"stack": string(debug.Stack()), // DANGEROUS - exposes internal details
})
}
// ... create post logic
return c.JSON(http.StatusCreated, post)
}
Echo Go's default error handling can also leak sensitive information. Without proper configuration, internal server errors return detailed error messages that may contain database queries, file paths, or environment variables:
e := echo.New()
// Default: returns detailed errors in production
Echo Go's middleware ecosystem can also introduce data exposure through logging. If you're not careful with what gets logged, sensitive request data can end up in log files:
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: "${method} ${uri} ${status} ${error} ${latency_human} ${body} \n",
}))
This logs the entire request body, which might contain passwords, tokens, or personal data. Additionally, Echo Go's default binder doesn't automatically mask sensitive fields when binding JSON requests, potentially exposing them in debug logs or error responses.
Echo Go-Specific Detection
Detecting data exposure in Echo Go applications requires both static analysis and runtime scanning. For static analysis, examine your Echo Go handlers for patterns that might leak sensitive data. Look for direct JSON marshaling of struct fields without considering what's being exposed:
// Problematic: directly exposing internal struct
func getInternalData(c echo.Context) error {
data := internalService.GetSensitiveData()
return c.JSON(http.StatusOK, data) // May expose more than intended
}
Run middleBrick's API security scanner against your Echo Go endpoints to identify data exposure vulnerabilities. The scanner tests unauthenticated endpoints and analyzes responses for sensitive information patterns:
npm install -g middlebrick
middlebrick scan https://your-echo-app.com/api/users
middleBrick specifically checks for:
- Database identifiers (MongoDB ObjectIds, PostgreSQL UUIDs)
- Internal system metadata
- Stack traces in error responses
- Debug information in production responses
- Excessive data exposure in API responses
For runtime detection, implement Echo Go middleware that inspects responses before they're sent:
func dataExposureMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
err := next(c)
// Check if response contains sensitive data
if resp, ok := c.Get("response").(map[string]interface{}); ok {
if containsSensitiveData(resp) {
// Log and handle appropriately
log.Warn().Interface("response", resp).Msg("Potential data exposure detected")
}
}
return err
}
}
Echo Go's validation system can help detect when sensitive data is being processed. Use the validator middleware to ensure request data meets security requirements:
e.Validator = &customValidator{validator: validator.New()}
Implement response filtering middleware to sanitize sensitive fields before they leave your Echo Go application:
func sanitizeResponseMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
err := next(c)
// Get the response body
body, err := io.ReadAll(c.Response().Writer)
if err != nil {
return err
}
// Sanitize sensitive data
sanitized := sanitizeSensitiveData(body)
// Write back sanitized response
_, err = c.Response().Writer.Write(sanitized)
return err
}
}
Echo Go-Specific Remediation
Remediate data exposure in Echo Go by implementing proper response modeling and sanitization. Start by creating explicit response DTOs that only include necessary fields:
type UserResponse struct {
ID string `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
}
type SecureUserResponse struct {
ID string `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
// No internal IDs, no timestamps, no metadata
}
func getUserHandler(c echo.Context) error {
id := c.Param("id")
user, err := db.GetUserByID(id)
if err != nil {
return c.JSON(http.StatusNotFound, map[string]string{"error": "User not found"})
}
// Map to secure response
response := SecureUserResponse{
ID: obfuscateID(user.ID),
Email: user.Email,
Username: user.Username,
}
return c.JSON(http.StatusOK, response)
}
func obfuscateID(id string) string {
// Return a non-sequential, non-guessable identifier
return fmt.Sprintf("user_%d", hashID(id))
}
Implement Echo Go middleware to catch and sanitize error responses before they're sent to clients:
func errorSanitizationMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
err := next(c)
// Check for internal errors
if echoErr, ok := err.(*echo.HTTPError); ok {
if echoErr.Code == http.StatusInternalServerError {
// Log the full error internally
log.Error().Err(err).Msg("Internal server error")
// Return sanitized error to client
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": "Internal server error",
// No stack traces, no internal details
})
}
}
return err
}
}
Use Echo Go's custom binder to mask sensitive fields during request processing:
type SecureBinder struct{}
func (sb *SecureBinder) Bind(i interface{}, c echo.Context) error {
if err := c.Bind(i); err != nil {
return err
}
// Mask sensitive fields after binding
if user, ok := i.(*User); ok {
user.Password = "" // Clear password after use
}
return nil
}
// In main setup
e := echo.New()
e.Binder = &SecureBinder{}
Implement response filtering to prevent sensitive data from being logged:
func loggingMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Capture request
req := c.Request()
// Filter sensitive headers before logging
filteredHeaders := filterSensitiveHeaders(req.Header)
// Call next handler
err := next(c)
// Filter sensitive data from response before logging
if resp, ok := c.Get("response").(map[string]interface{}); ok {
filteredResp := filterSensitiveData(resp)
log.Info().Interface("response", filteredResp).Msg("API response")
}
return err
}
}
func filterSensitiveData(data map[string]interface{}) map[string]interface{} {
filtered := make(map[string]interface{})
for k, v := range data {
if isSensitiveField(k) {
filtered[k] = "[FILTERED]"
} else {
filtered[k] = v
}
}
return filtered
}
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |