HIGH injection flawsecho gofirestore

Injection Flaws in Echo Go with Firestore

Injection Flaws in Echo Go with Firestore — how this specific combination creates or exposes the vulnerability

Injection flaws in an Echo Go service that uses Firestore typically arise when untrusted input is used to build queries, paths, or filter values that are passed to the Firestore client. If input is concatenated into query constraints or used to construct document references without validation and encoding, an attacker can manipulate the query logic or traverse the database in unintended ways.

Echo Go does not introduce a database layer itself; it is an HTTP framework. The risk comes from how the application builds Firestore interactions using request data. For example, using a path parameter directly as a document ID or collection name can enable IDOR or traversal across tenant boundaries. Consider a route like /orgs/{orgID}/documents/{docID}: if the handler does not validate orgID and docID and uses them naively to form Firestore references, an attacker can supply IDs from other organizations to read or write unauthorized documents.

Another common pattern is constructing query filters with raw user input, such as field names or operator values. If a field name is taken from a query parameter and injected into a Firestore query without allowlisting, this can lead to unintended data access. For instance, an attacker could provide ?field=__name__ or other internal fields to expose documents that should remain restricted. Similarly, numeric or type confusion can cause queries to match more documents than intended, effectively bypassing intended access boundaries.

Firestore’s server-side evaluation also means that malformed or overly broad queries can return large result sets, amplifying exposure. While Firestore enforces its own security rules, those rules are only as strong as the queries sent from the application. An injection-style bug in the Go code can bypass intended scoping, making security rules insufficient on their own. This is especially critical in multi-tenant designs where data isolation depends on precise query construction.

In addition to query injection, path manipulation can lead to issues involving the database’s hierarchical model. If document references are assembled using string concatenation rather than using the Firestore SDK’s reference-building functions, it becomes easier to inject invalid paths or traverse to sensitive collections. For example, using collection(db, "orgs/" + orgID + "/documents") without strict validation is riskier than using collection(docRef, "documents") from a properly scoped parent reference.

Because middleBrick scans the unauthenticated attack surface, it can surface these risks by observing responses that indicate data leakage or inconsistent behavior based on manipulated input. Findings often highlight missing input validation, improper use of Firestore queries, and weak reference construction. Remediation guidance typically focuses on strict allowlisting, using SDK methods to build references, and ensuring that authorization checks are applied close to the data access layer.

Firestore-Specific Remediation in Echo Go — concrete code fixes

To reduce injection risk when using Firestore with Echo Go, validate and sanitize all inputs before constructing queries or references. Use allowlists for field names, avoid string concatenation for paths, and rely on the Firestore SDK to build references safely.

Validate and scope inputs

Always validate path parameters against expected patterns and scope them to the correct tenant or user. Do not trust client-supplied IDs for constructing references directly.

type DocumentRequest struct {
    OrgID string `json:"orgId"`
    DocID string `json:"docId"`
}

func isValidOrgID(orgID string) bool {
    // Allow only alphanumeric and hyphens, with length limits
    matched, _ := regexp.MatchString(`^[a-zA-Z0-9\-]{1,64}$`, orgID)
    return matched
}

func isValidDocID(docID string) bool {
    // Avoid characters that can traverse paths
    matched, _ := regexp.MatchString(`^[a-zA-Z0-9_\-]{1,128}$`, docID)
    return matched
}

func getDocument(c echo.Context) error {
    req := new(DocumentRequest)
    if err := c.Bind(req); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid request")
    }
    if !isValidOrgID(req.OrgID) || !isValidDocID(req.DocID) {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid identifiers")
    }

    ctx := c.Request().Context()
    client, err := firestore.NewClient(ctx, "your-project-id")
    if err != nil {
        return echo.NewHTTPError(http.StatusInternalServerError, "unable to create client")
    }
    defer client.Close()

    docRef := client.Collection("orgs").Doc(req.OrgID).Collection("documents").Doc(req.DocID)
    snap, err := docRef.Get(ctx)
    if err != nil {
        return echo.NewHTTPError(http.StatusInternalServerError, "unable to fetch document")
    }
    if !snap.Exists() {
        return echo.NewHTTPError(http.StatusNotFound, "document not found")
    }
    return c.JSON(http.StatusOK, snap.Data())
}

Use allowlists for field names

When a field name is supplied by the client, map it to a known safe field instead of injecting it directly into the query.

func queryDocuments(c echo.Context) error {
    field := c.QueryParam("field")
    // Map allowed field names to Firestore field names
    allowed := map[string]string{
        "status":  "status",
        "created": "createTime",
        "updated": "updateTime",
    }
    f, ok := allowed[field]
    if !ok {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid field")
    }

    const limit = 10
    iter := client.Collection("documents").OrderBy(f, firestore.Asc).Limit(limit).Documents(ctx)
    var results []map[string]interface{}
    for {
        snap, err := iter.Next()
        if err == iterator.Done {
            break
        }
        if err != nil {
            return echo.NewHTTPError(http.StatusInternalServerError, "query failed")
        }
        results = append(results, snap.Data())
    }
    return c.JSON(http.StatusOK, results)
}

Build references safely

Use the Firestore SDK to construct references rather than string concatenation. This reduces the risk of path injection and makes scoping clearer.

func createDocument(c echo.Context) error {
    orgID := c.Param("orgID")
    if !isValidOrgID(orgID) {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid orgID")
    }

    parent := client.Collection("orgs").Doc(orgID)
    docRef := parent.Collection("documents").NewDoc()
    // or use a known ID with validation
    // docRef := parent.Collection("documents").Doc(validatedID)

    data := map[string]interface{}{
        "content": c.Request().FormValue("content"),
        "createTime": time.Now(),
    }
    _, err := docRef.Set(ctx, data)
    if err != nil {
        return echo.NewHTTPError(http.StatusInternalServerError, "unable to create document")
    }
    return c.NoContent(http.StatusCreated)
}

Apply consistent scoping and rules awareness

Design queries to respect tenant boundaries at the application level, even when security rules also enforce it. Use Firestore transactions or batched reads when consistency is required, and avoid exposing internal field names in APIs.

Leverage middleBrick for continuous checks

With the middleBrick Web Dashboard or the CLI (middlebrick scan <url>), you can regularly scan your endpoints to detect injection-related findings. The Pro plan adds continuous monitoring so regressions are caught early, and the GitHub Action can fail builds if risk scores drop below your chosen threshold.

Frequently Asked Questions

Can Firestore security rules alone prevent injection issues in Echo Go?
Firestore security rules provide an important layer, but they cannot fully compensate for injection flaws in application code. Rules are evaluated per request and can be too broad; malformed or overly permissive queries can still expose unintended data. Input validation, safe reference construction, and query design in your Echo Go service are essential to prevent injection issues.
How does middleBrick help detect injection risks in an API using Firestore?
middleBrick runs black-box checks against the unauthenticated attack surface, including tests that probe for IDOR, improper scoping, and data exposure through query manipulation. It cross-references OpenAPI specs with runtime behavior and provides findings with severity and remediation guidance, helping you identify injection risks specific to your Firestore integration.