Dns Rebinding in Gin with Cockroachdb
Dns Rebinding in Gin with Cockroachdb — how this specific combination creates or exposes the vulnerability
DNS rebinding is a client-side attack where an attacker causes a victim’s browser to resolve a domain name to an IP address that is different from the initially resolved address, often bypassing same-origin policy and private network restrictions. When a Go web application built with Gin exposes a Cockroachdb-backed endpoint that performs database operations based on attacker-influenced input, DNS rebinding can turn an apparently safe outbound connection into a vector for unauthorized access or data leakage.
Consider a Gin handler that accepts a hostname or hostport from the client and uses it to open a SQL connection to Cockroachdb. If the handler does not strictly validate or restrict the target host, an attacker can supply a domain they control and chain DNS rebinding to make that domain first resolve to a public IP (to pass any allowlists) and later resolve to an internal Cockroachdb node (for example, localhost:26257 or an internal Kubernetes service IP). Because the browser or backend-initiated request follows the updated DNS record, the Gin application may open a connection to the internal Cockroachdb instance on behalf of the attacker, exposing cluster-internal services that are normally not reachable from the application’s network zone.
This risk is especially relevant when Cockroachdb is deployed in a restricted network and access is controlled by IP allowlists. The Gin application itself may be publicly reachable; DNS rebinding can bypass those perimeter controls by abusing the application’s trust in client-supplied host information. Even if Cockroachdb requires TLS and username/password, leaking credentials or session tokens via other vectors (e.g., insufficient input validation) can compound the impact. An attacker may probe internal endpoints via crafted HTTP requests that trigger SQL queries or status checks, effectively using the Gin layer as a pivot point.
In practice, this maps to common OWASP API Top 10 categories such as Server-Side Request Forgery (SSRF) and Improper Access Control. Since middleBrick checks for SSRF and input validation issues across 12 parallel security checks, it can highlight suspicious patterns where user-controlled network destinations intersect with sensitive backend services like Cockroachdb. The scanner does not fix the routing or network setup, but its findings with remediation guidance help developers understand how DNS rebinding can combine with misconfigured endpoints to expose Cockroachdb.
Cockroachdb-Specific Remediation in Gin — concrete code fixes
To prevent DNS rebinding and related SSRF-style issues in a Gin application that talks to Cockroachdb, enforce strict allowlisting of database hosts and avoid dynamic host resolution based on client input. Use fixed connection parameters and, when necessary, validate targets against a whitelist of internal host patterns. Below are concrete, working examples for Gin handlers that safely interact with Cockroachdb.
Example 1: Static Cockroachdb connection in Gin
Define the database connection at initialization time using a constant or configuration value that is not influenced by client requests. This eliminates the possibility of an attacker steering the connection through rebinding or other means.
package main
import (
"context"
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/lib/pq"
)
const cockroachConnStr = "postgresql://root@localhost:26257/defaultdb?sslmode=require"
var db *sql.DB
func init() {
var err error
db, err = sql.Open("postgres", cockroachConnStr)
if err != nil {
log.Fatalf("failed to connect to Cockroachdb: %v", err)
}
if err := db.Ping(); err != nil {
log.Fatalf("failed to ping Cockroachdb: %v", err)
}
}
func SafeHandler(c *gin.Context) {
var result string
if err := db.QueryRowContext(c.Request.Context(), "SELECT current_database()").Scan(&result); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"database": result})
}
func main() {
r := gin.Default()
r.GET("/health", SafeHandler)
r.Run(":8080")
}
Example 2: Parameterized queries with strict input validation
If your use case requires dynamic elements (e.g., selecting a database name), validate against a strict allowlist and use parameterized queries to avoid injection and unintended routing. Do not concatenate user input into connection strings or SQL identifiers.
var allowedDatabases = map[string]bool{
"appdb": true,
"metrics": true,
}
func ValidatedDBHandler(c *gin.Context) {
dbName := c.Query("db")
if !allowedDatabases[dbName] {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid database"})
return
}
connStr := "postgresql://root@localhost:26257/" + dbName + "?sslmode=require"
ctx := c.Request.Context()
rows, err := db.QueryContext(ctx, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer rows.Close()
var tables []string
for rows.Next() {
var t string
if err := rows.Scan(&t); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
tables = append(tables, t)
}
c.JSON(http.StatusOK, gin.H{"tables": tables})
}
Operational and network-level safeguards
While code-level fixes are essential, combine them with infrastructure practices that reduce exposure to DNS rebinding: keep Cockroachdb bound to private interfaces, use firewall rules to block unexpected source IPs, and avoid exposing administrative ports to public traffic. middleBrick can highlight SSRF and input validation findings that are relevant to this setup, but remediation requires developers to enforce host allowlists and validate all external inputs.