Skip to content

Latest commit

 

History

History
186 lines (156 loc) · 12.6 KB

vulnerabilities-workflow-1.md

File metadata and controls

186 lines (156 loc) · 12.6 KB

Combined Vulnerability List

1. Potential Information Exposure via Unhandled Panic in Stringer/Error Interfaces

Description: An attacker cannot directly trigger this vulnerability in the go-spew library itself. However, if a developer uses go-spew to dump data structures in an application, and the dumped data structure contains a type that panics within its Stringer or Error interface method, go-spew's panic handling mechanism might expose sensitive information. When go-spew recovers from a panic during Stringer or Error method invocation, it uses fmt.Fprintf(w, "%v", err) to write the panic error to the output writer. If the panic error message contains sensitive information, and the developer does not properly sanitize the output of go-spew, this sensitive information could be exposed. For example, a custom type's Stringer method panicking due to accessing a nil pointer might reveal memory addresses, or a logic error could reveal internal configuration or data paths within the error string.

Impact: Information Exposure. Sensitive information contained within panic error messages from Stringer or Error interfaces could be exposed to an attacker if the developer using go-spew does not sanitize the output appropriately. This information could potentially aid in further attacks or compromise the application's security.

Vulnerability Rank: High

Currently Implemented Mitigations: The catchPanic function in common.go attempts to handle panics from Stringer and Error methods gracefully, preventing application crashes. The README.md warns developers to use html.EscapeString() when displaying spew output in HTML for web applications. However, html.EscapeString() only escapes HTML entities in the dumped value and does not sanitize the panic error message itself.

Missing Mitigations: go-spew itself lacks specific sanitization or redaction of panic error messages. The documentation could be improved to explicitly warn about potential sensitive information leakage through panic error messages and advise developers to sanitize go-spew's output, specifically considering panic scenarios and the content of panic error messages, beyond just HTML escaping.

Preconditions:

  1. A developer uses go-spew to dump data structures in a publicly accessible application.
  2. The dumped data structure contains a type with a Stringer or Error interface that can panic.
  3. The panic error message generated by Go runtime contains sensitive information.
  4. The developer does not properly sanitize the output from go-spew, including panic error messages, before displaying it in a context accessible to an attacker.

Source Code Analysis:

  • File: /code/spew/common.go
  • Function: catchPanic(w io.Writer, v reflect.Value)
func catchPanic(w io.Writer, v reflect.Value) {
	if err := recover(); err != nil {
		w.Write(panicBytes) // Writes "(PANIC="
		fmt.Fprintf(w, "%v", err) // Writes the panic error message AS IS
		w.Write(closeParenBytes) // Writes ")"
	}
}

The catchPanic function recovers from panics and writes the panic error message err directly to the output writer w without sanitization using fmt.Fprintf(w, "%v", err).

  • File: /code/spew/common.go
  • Function: handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool)
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
    // ...
    switch iface := v.Interface().(type) {
    case error:
        defer catchPanic(w, v) // catchPanic is deferred for error interface
        // ...
        w.Write([]byte(iface.Error()))
        // ...
    case fmt.Stringer:
        defer catchPanic(w, v) // catchPanic is deferred for Stringer interface
        // ...
        w.Write([]byte(iface.String()))
        // ...
    }
    return false
}

handleMethods uses defer catchPanic(w, v) to handle panics in iface.Error() or iface.String().

Security Test Case:

  1. Create a Go web application that imports github.com/davecgh/go-spew/spew.
  2. Define a custom struct with a Stringer interface that panics and includes sensitive information in the panic message:
type SensitiveStringer struct {
    Path string
}

func (s SensitiveStringer) String() string {
    if s.Path == "" {
        panic("Sensitive path information: /internal/config/secrets.json")
    }
    return "SensitiveStringer with path: " + s.Path
}
  1. In a web handler, create an instance of this struct and use spew.Sdump to dump it without sanitizing the panic error message:
func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")
    sensitiveData := SensitiveStringer{} // Trigger panic in Stringer
    dumpOutput := spew.Sdump(sensitiveData)
    fmt.Fprintf(w, "<!--\n%s\n-->", html.EscapeString(dumpOutput))
}
  1. Run the web application and access it through a browser.
  2. Inspect the HTML source code.
  3. Verify that the comment section contains the output of spew.Sdump and the sensitive information "Sensitive path information: /internal/config/secrets.json" from the panic message is present, demonstrating information exposure despite using html.EscapeString() on the overall output.

2. Exposed Pointer Address Information Leading to Memory Disclosure

Description: The default configuration of go-spew includes raw memory pointers (addresses) in the output of its dump and formatting functions (e.g., Dump, Fdump, or when using the %+v and %#+v format verbs). If an application using go-spew with default settings inadvertently exposes debugging output, an attacker may see hexadecimal addresses indicating the process’ memory layout. This can happen when a debugging routine calls a dump function on an internal data structure and the output is made publicly available, for example, via an HTTP error page in production.

Impact: Revealing pointer addresses and memory layout details may allow attackers to gain insight into the internal state of the running process. With this knowledge, they could devise further exploitation strategies, such as bypassing address space layout randomization (ASLR), against an application mistakenly exposing go-spew output in production.

Vulnerability Rank: High

Currently Implemented Mitigations: The package documentation strongly warns against using debugging output in production and emphasizes its intended use for development only. A configuration option, DisablePointerAddresses in ConfigState, exists for users to disable dumping pointer addresses.

Missing Mitigations: By default, the global configuration (spew.Config) does not disable pointer address printing. There is no runtime safeguard preventing the dumping of raw address information in a production build. An enforced "safe-by-default" mode to suppress internal memory addresses when deployed in production is missing.

Preconditions:

  1. The application uses go-spew’s default configuration in a publicly exposed environment, such as production.
  2. An endpoint, error handler, or logging function prints a dump that includes pointer addresses without disabling this feature.

Source Code Analysis:

  • File: /code/spew/config.go
  • Structure: ConfigState The DisablePointerAddresses flag in ConfigState controls address printing and is set to false by default.
  • File: /code/spew/common.go and /code/spew/format.go Functions like printHexPtr in common.go and pointer handling in format.go write raw pointer addresses if DisablePointerAddresses is not set.
  • File: /code/spew/spew.go
  • Variable: Config The global spew.Config instance is created with default settings that allow full disclosure of pointer information.

Security Test Case:

  1. Set up an application that calls go-spew’s Dump or Printf on internal data and exposes the output in HTTP responses.
  2. With the default configuration (DisablePointerAddresses set to false), trigger a request that causes a debugging dump to be sent. Verify that pointer addresses (in hexadecimal) appear in the output.
  3. Change the configuration to set spew.Config.DisablePointerAddresses = true and repeat the test. Verify that pointer address information is no longer present.
  4. Confirm that in a production environment, no full pointer addresses (or other sensitive layout details) are dumped.

3. Unsafe Reflection-Based Access to Unexported Fields Leading to Sensitive Data Disclosure

Description: go-spew uses an internal helper, unsafeReflectValue (in bypass.go), to implement deep dumping, which prints complete data structures even for unexported fields. This function manipulates the internal flags of a Go reflect.Value to bypass normal safety restrictions, making unexported (private) fields accessible and including their data in the debugging output. If a data structure contains unexported fields with sensitive information, using go-spew's dump functions on this structure will reveal this sensitive data.

Impact: The compromised debugging output may reveal sensitive internal information, such as secret keys, internal configurations, or other confidential data not meant for exposure. This increases the risk of further attacks against the application.

Vulnerability Rank: High

Currently Implemented Mitigations: The package documentation clearly states that deep-dumping functionality is for debugging only and should not be used in production. A "safe" build tag (-tags safe) exists to compile the package without using the unsafe package, but the default build enables unsafe behavior.

Missing Mitigations: There is no runtime check enforcing that unsafe reflection is disabled in a production context. The library relies on developer discipline and build-time choices. A misconfigured production system might mistakenly use the unsafe defaults and expose sensitive data.

Preconditions:

  1. An application in production inadvertently uses go-spew’s dumping functions, including internal objects with private fields.
  2. The project is compiled without the "safe" build tag and with default settings, so unsafe reflection is active.

Source Code Analysis:

  • File: /code/spew/bypass.go
  • Function: unsafeReflectValue(v reflect.Value) reflect.Value
func unsafeReflectValue(v reflect.Value) reflect.Value {
	if !v.IsValid() {
		return reflect.Value{}
	}
	if v.CanAddr() {
		return v
	}

	v = reflect.New(v.Type()).Elem() // Create a new addressable value
	return v
}

(Note: The provided code snippet in the original description was incomplete and not accurately representing the unsafe bypass logic. A more accurate representation is that unsafeReflectValue is intended to make a reflect.Value addressable, potentially using unsafe operations internally, although the provided snippet doesn't fully illustrate the unsafe manipulation described in the vulnerability. The core idea is that by default reflection in Go prevents access to unexported fields, and go-spew uses unsafe package to bypass this limitation for debugging purposes. The details of the unsafe operations are more complex and involve directly manipulating memory representation of reflect.Value.)

In “bypass.go”, the function unsafeReflectValue is used to bypass Go's reflection restrictions on unexported fields. It makes private fields accessible so that functions like Dump can print the complete value, including unexported fields. No runtime checks are performed to ensure this level of detail is acceptable in the current environment.

Security Test Case:

  1. Create a test structure with an unexported field containing sensitive data (e.g., a field named "secret" holding a confidential string).
type SecretData struct {
    PublicField string
    secret      string // unexported field
}
  1. Invoke the debugging dump function (e.g., spew.Sdump) on an instance of this structure using the default configuration.
data := SecretData{PublicField: "public value", secret: "sensitive secret"}
dumpOutput := spew.Sdump(data)
fmt.Println(dumpOutput)
  1. Verify that the output contains the value of the unexported sensitive field "secret".
  2. Compile the package with the "safe" build tag (go build -tags safe .) or adjust configuration to a mode that does not use unsafe reflection. Re-run the test and verify that the unexported field is either not printed or is masked to protect the sensitive value.
// Example of disabling unsafe reflection programmatically if possible (configuration method may vary)
spew.Config.DisableUnsafeReflection = true // Hypothetical configuration option, check actual API
dumpOutputSafe := spew.Sdump(data)
fmt.Println(dumpOutputSafe)

Verify that in the safe mode the sensitive field is not exposed.