Xml External Entities in Echo Go with Mongodb
Xml External Entities in Echo Go with Mongodb — how this specific combination creates or exposes the vulnerability
An XML External Entity (XXE) vulnerability occurs when an application processes XML input that references external entities. In Go services built with the Echo framework, if XML parsing is enabled and user-controlled XML is accepted, an attacker can define entities that read local files, trigger SSRF, or cause denial of service. When the parsed data is used to build or query a MongoDB database, the impact can extend to data exposure or injection depending on how the application uses the extracted information.
Consider an Echo endpoint that receives an XML payload containing a filename or a MongoDB query specification defined via an external entity. A typical vulnerable handler might decode the XML and directly use the extracted values in a MongoDB operation without validation. Because Echo does not enable XML parsing by default, the risk is introduced only when developers explicitly add an XML decoder (for example via encoding/xml) and bind the decoded fields into database commands. If the XML references an external entity such as &file; that resolves to /etc/passwd, the server may disclose sensitive data. If the entity resolves to a file containing JSON-like configuration that is then interpreted as a MongoDB filter, the filter may be manipulated to bypass intended access controls.
The interaction with MongoDB becomes significant when extracted XML content is used to construct filters for operations like Find or Aggregate. For example, an external entity could inject additional keys or operators into the filter, potentially leading to unauthorized data access. In a typical vulnerable pattern, the application unmarshals XML into a generic map or struct and then passes that map directly to collection.Find. Because the map may now contain attacker-controlled keys, the query may behave unexpectedly, especially if field names or values are interpreted in a broader context (such as with regex patterns or collation settings).
Another angle involves logging or error messages. If an XXE triggers a MongoDB error (for instance, due to malformed input derived from an external entity), detailed stack traces or field names may be returned to the client. These disclosures can aid further attacks. Moreover, if the application uses the extracted XML content to dynamically build update operations (e.g., using $set with values sourced from XML), an attacker may influence write behavior in ways that were not intended by the API design.
To detect this specific combination, scanners can analyze whether the service accepts XML content types (such as application/xml or text/xml) and whether it performs any XML unmarshaling before MongoDB interactions. They also look for patterns where external entity resolution is possible (for example, use of xml.NewDecoder without disabling entity resolution) and whether data derived from XML is used in database queries. middleBrick runs checks that surface these risk patterns and maps findings to relevant parts of the OWASP API Top 10 and compliance frameworks, providing remediation guidance rather than attempting to fix the code.
Mongodb-Specific Remediation in Echo Go — concrete code fixes
Remediation focuses on two aspects: disabling external entity resolution in XML processing and ensuring that data extracted from XML is never directly used to construct MongoDB operations without strict validation and type constraints.
Disable XML External Entities
In Go, you can prevent XXE by using an XML decoder with Entity and CharData handling that does not resolve external references. Avoid xml.Unmarshal on untrusted input when external entities are a concern. Instead, use a decoder with a custom resolver that returns errors for external entities.
package main
import (
"encoding/xml"
"net/http"
"github.com/labstack/echo/v4"
)
type SafeXMLPayload struct {
Field string `xml:"field"`
}
func handler(c echo.Context) error {
dec := xml.NewDecoder(c.Request().Body)
dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
return input, nil
}
// Disable DOCTYPE and external entities by not calling
// xml.DTD support; simply reject XML that contains <!ENTITY
var payload SafeXMLPayload
if err := dec.Decode(&payload); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid xml"})
}
// Validate payload.Field before using it
if payload.Field == "" {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "missing field"})
}
// Safe usage with MongoDB
filter := bson.M{"name": payload.Field}
var result bson.M
if err := collection.FindOne(c.Request().Context(), filter).Decode(&result); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "database error"})
}
return c.JSON(http.StatusOK, result)
}
Validate and Restrict Data Flow to MongoDB
Never construct MongoDB filters from raw XML maps. Use strongly typed structs and whitelist field names. If you must accept dynamic queries, validate each key against an allowlist and use parameterized updates instead of injecting raw values into the query object.
import (
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
// Whitelisted filter fields
var allowedFields = map[string]bool{
"name": true,
"status": true,
}
func buildFilter(data map[string]interface{}) (bson.M, error) {
filter := bson.M{}
for k, v := range data {
if !allowedFields[k] {
return nil, fmt.Errorf("field not allowed: %s", k)
}
filter[bson.M{k}] = v
}
return filter, nil
}
// Usage inside an Echo handler after safe XML decoding
rawMap := map[string]interface{}{"name": "example"} // from validated source
filter, err := buildFilter(rawMap)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
var doc bson.M
if err := collection.FindOne(c.Request().Context(), filter).Decode(&doc); err != nil {
if err == mongo.ErrNoDocuments {
return c.JSON(http.StatusNotFound, nil)
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "database error"})
}
return c.JSON(http.StatusOK, doc)
Content-Type and Input Validation
Ensure your Echo routes explicitly expect JSON for endpoints that do not need XML. If XML is required, enforce strict schema validation and reject DOCTYPE declarations. Combine this with runtime security tooling that flags routes accepting XML without entity resolution disabled.