Skip to main content

Technical information leak - Stacktrace

Need

Prevention of technical information leakage from system error traces

Context

  • Usage of Go 1.16 for building high-performance and scalable applications
  • Usage of gin-gonic/gin for building web applications in Go
  • Usage of net/http for creating HTTP servers in a Node.js application

Description

Non compliant code

package main

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
r := gin.Default()

r.GET("/ping", func(c *gin.Context) {
var result map[string]interface{}
err := SomeFunctionThatCouldFail(result)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
}
})

r.Run()
}

func SomeFunctionThatCouldFail(result map[string]interface{}) error {
// some code that could return an error
return nil
}

In the above code, a /ping endpoint is defined using the Gin framework in Go. The handler for this endpoint calls a function SomeFunctionThatCouldFail(result), which might return an error.

If the function returns an error, the error message is directly sent back to the client as JSON response with status code 500. This is a technical information leak vulnerability, as the error message can contain sensitive information such as stack traces, which should not be exposed to the client.

The error message can provide an attacker with insights into the internal workings of the application, which can be exploited for further attacks. For example, it can reveal information about the software stack, database schema, or other internal configurations.

Steps

  • Implement proper error handling in the SomeFunctionThatCouldFail function to handle any potential errors.
  • Instead of directly returning the error, log the error message without exposing any sensitive information.
  • Modify the error response in the main function to return a generic error message instead of the actual error message.
  • Avoid returning the full stack trace in the error response to prevent leaking technical information.
  • Consider using a centralized error handling mechanism to handle and log errors consistently across the application.

Compliant code

package main

import (
"github.com/gin-gonic/gin"
"log"
"net/http"
)

func main() {
r := gin.Default()

r.GET("/ping", func(c *gin.Context) {
var result map[string]interface{}
err := SomeFunctionThatCouldFail(result)
if err != nil {
log.Printf("Error: %v", err) // Log the error without exposing it
c.JSON(http.StatusInternalServerError, gin.H{"error": "An internal server error occurred"})
} else {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
}
})

r.Run()
}

func SomeFunctionThatCouldFail(result map[string]interface{}) error {
// some code that could return an error
return nil
}

The updated code now includes proper error handling to prevent the leakage of technical information.

  1. The function SomeFunctionThatCouldFail is still expected to return an error if it fails. However, instead of directly returning this error to the client, it is now logged on the server side using log.Printf. This allows developers to still have access to the error details for debugging purposes, without exposing this information to the client.

  2. In the main function, if an error occurs, a generic error message "An internal server error occurred" is returned to the client. This message does not reveal any technical details about the error, thus preventing information leakage.

  3. The full stack trace is no longer returned in the error response. This is achieved by not directly returning the error from SomeFunctionThatCouldFail to the client.

  4. This approach can be extended to a centralized error handling mechanism where all errors are handled and logged in a consistent manner across the application. This would involve defining a custom error type and a central function to handle these errors. This function would log the error details and return a generic error message to the client.

References