Data Exposure in Chi with Cockroachdb
Data Exposure in Chi with Cockroachdb — how this specific combination creates or exposes the vulnerability
The Data Exposure check in middleBrick examines whether API responses inadvertently return sensitive information such as personal data, secrets, or internal identifiers. When an API is built with the Chi framework and uses Cockroachdb as its backend, specific patterns in SQL handling and JSON serialization can amplify the risk of data exposure.
Chi is a lightweight, idiomatic HTTP router and middleware stack for Go. In a typical Chi-based service that uses Cockroachdb, developers may construct SQL queries dynamically or rely on ORM-like patterns that pull rows from Cockroachdb and marshal them directly into JSON responses. If column selection is too broad—for example, selecting all columns with SELECT *—the query can return sensitive fields such as internal IDs, timestamps, or even authentication tokens that should never be exposed to clients.
Cockroachdb, while compatible with PostgreSQL wire protocol and drivers, has its own system columns and default behaviors that can contribute to data exposure if not handled carefully. When using the standard database/sql package with a Cockroachdb driver, queries that do not explicitly limit columns may return sensitive metadata. Additionally, if struct fields intended for internal use are exported (capitalized) and included in JSON responses, they can leak information such as database IDs or operational details.
Another vector specific to this combination involves improper handling of query results. For instance, failing to validate or sanitize retrieved data before embedding it in a JSON payload can result in sensitive fields being included in API responses. A common pattern is to scan rows into a struct that contains fields like PasswordHash or APIKey, which should never be serialized. Even if the frontend ignores these fields, the response still carries them over the network, increasing the data exposure footprint.
middleBrick’s Data Exposure check looks for these patterns by analyzing the OpenAPI specification and correlating it with runtime responses. For a Chi service with Cockroachdb, it flags responses that include fields such as created_at, updated_at, or any column that could be tied to internal state. The scanner also checks for missing field filtering, overly broad struct embedding, and the presence of sensitive tags that are not respected during JSON serialization.
To illustrate the risk, consider an endpoint that retrieves a user record from Cockroachdb and returns it as JSON. If the handler uses a broad query and a struct that includes sensitive fields, the response may unintentionally expose private data. middleBrick detects such patterns and provides prioritized findings with severity levels and remediation guidance, helping developers tighten data exposure controls without disrupting existing workflows.
Cockroachdb-Specific Remediation in Chi — concrete code fixes
Remediation focuses on precise query definitions, strict struct usage, and disciplined JSON serialization. By narrowing the data retrieved from Cockroachdb and controlling which fields are exposed, you can substantially reduce the data exposure surface for Chi-based APIs.
1. Explicit column selection and struct mapping
Instead of using SELECT *, explicitly list the columns you need and map them to a struct that only includes fields intended for output. This prevents sensitive columns from being pulled or serialized.
// Chi handler with explicit column selection
package handlers
import (
"database/sql"
"encoding/json"
"net/http"
"github.com/go-chi/chi/v5"
_ "github.com/lib/pq"
)
type UserPublic struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
CreatedAt string `json:"created_at"`
}
func GetUserPublic(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
userID := chi.URLParam(r, "userID")
var user UserPublic
// Explicit columns avoid exposing sensitive fields from Cockroachdb
row := db.QueryRow("SELECT id, username, email, created_at FROM users WHERE id = $1", userID)
if err := row.Scan(&user.ID, &user.Username, &user.Email, &user.CreatedAt); err != nil {
http.Error(w, "user not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
}
2. Avoid embedding sensitive or internal structs
Do not embed internal or administrative structs that may contain fields like PasswordHash, APIKey, or IsAdmin. Define separate output structs for API responses and copy only safe fields.
// Safe mapping without embedding internal types
type UserInternal struct {
ID int
Username string
Email string
PasswordHash string
APIKey string
IsAdmin bool
CreatedAt string
}
type UserResponse struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
CreatedAt string `json:"created_at"`
}
func MapToUserResponse(in UserInternal) UserResponse {
return UserResponse{
ID: in.ID,
Username: in.Username,
Email: in.Email,
CreatedAt: in.CreatedAt,
}
}
3. Use context and query constraints with Cockroachdb
When querying Cockroachdb from Chi, use context and limit clauses to control result size and avoid leaking excess data. This also aligns with secure query practices and reduces the chance of accidental data exposure.
// Query with context and limits
package handlers
import (
"context"
"database/sql"
"net/http"
"github.com/go-chi/chi/v5"
)
func ListUsers(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
rows, err := db.QueryContext(ctx, "SELECT id, username, email FROM users LIMIT $1", 100)
if err != nil {
http.Error(w, "failed to fetch users", http.StatusInternalServerError)
return
}
defer rows.Close()
var users []UserResponse
for rows.Next() {
var u UserResponse
if err := rows.Scan(&u.ID, &u.Username, &u.Email); err != nil {
http.Error(w, "scan error", http.StatusInternalServerError)
return
}
users = append(users, u)
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
}
4. Validate and sanitize field names in OpenAPI spec
Ensure your OpenAPI definitions reflect only the intended public fields. This helps middleBrick correlate spec expectations with runtime behavior and reduces the likelihood of undocumented sensitive fields appearing in responses.
paths:
/users/{userID}:
get:
summary: Get public user information
operationId: getUserPublic
responses:
200:
description: Public user data
content:
application/json:
schema:
type: object
properties:
id:
type: integer
username:
type: string
email:
type: string
created_at:
type: string
format: date-time
By combining explicit queries, strict struct separation, and careful schema design, you can mitigate data exposure risks for Chi applications backed by Cockroachdb. middleBrick’s Data Exposure check can help validate these practices by identifying fields that should not be publicly accessible.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |