Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[security] Potential Insecure Deserialization #575

Open
ZuhairORZaki opened this issue Dec 19, 2024 · 1 comment
Open

[security] Potential Insecure Deserialization #575

ZuhairORZaki opened this issue Dec 19, 2024 · 1 comment

Comments

@ZuhairORZaki
Copy link

Overview

In file: request.go, there is a function ReadEntity which handles HTTP request bodies. It looks for a suitable entity reader based on the Content-Type header and uses the reader for a default content type if no matching reader is found. It then uses that reader to read the request body into the provided entityPointer.

// ReadEntity checks the Accept header and reads the content into the entityPointer.
func (r *Request) ReadEntity(entityPointer interface{}) (err error) {
	contentType := r.Request.Header.Get(HEADER_ContentType)
	contentEncoding := r.Request.Header.Get(HEADER_ContentEncoding)

	// check if the request body needs decompression
	if ENCODING_GZIP == contentEncoding {
		gzipReader := currentCompressorProvider.AcquireGzipReader()
		defer currentCompressorProvider.ReleaseGzipReader(gzipReader)
		gzipReader.Reset(r.Request.Body)
		r.Request.Body = gzipReader
	} else if ENCODING_DEFLATE == contentEncoding {
		zlibReader, err := zlib.NewReader(r.Request.Body)
		if err != nil {
			return err
		}
		r.Request.Body = zlibReader
	}

	// lookup the EntityReader, use defaultRequestContentType if needed and provided
	entityReader, ok := entityAccessRegistry.accessorAt(contentType)
	if !ok {
		if len(defaultRequestContentType) != 0 {
			entityReader, ok = entityAccessRegistry.accessorAt(defaultRequestContentType)
		}
		if !ok {
			return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType)
		}
	}
	return entityReader.Read(r, entityPointer)
}

However the objects passed to ReadEntity are not validated to see if their fields hold appropriate values after deserialization. For example, in file: restful-resource-functions.go, the function postOne passes a Product object to ReadEntity for populating the objects's fields using data from the request body. But there is no subsequent content validation for the deserialized object.

func (p ProductResource) postOne(req *restful.Request, resp *restful.Response) {
	updatedProduct := new(Product)
	err := req.ReadEntity(updatedProduct)
	if err != nil { // bad request
		resp.WriteErrorString(http.StatusBadRequest, err.Error())
		return
	}
	log.Println("updating product with id:" + updatedProduct.Id)
}

This is a potential case of insecure deserialization.

References

Insecure deserialization - Go

Sponsorship and Support:

This work is done by the security researchers from OpenRefactory and is supported by the Open Source Security Foundation (OpenSSF): Project Alpha-Omega. Alpha-Omega is a project partnering with open source software project maintainers to systematically find new, as-yet-undiscovered vulnerabilities in open source code - and get them fixed - to improve global software supply chain security.

The bug is found by running the iCR tool by OpenRefactory, Inc. and then manually triaging the results.

@emicklei
Copy link
Owner

@ZuhairORZaki thank you for sharing this information. My first impression is that this is not a bug and not a problem specific to go-restful as it uses standard Go SDK behavior. I have to take some time to see if and what I want to do about this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants