# Golang Vulnerability Examples and Fixes

> **Use this page when:** reviewing Go APIs, platform services, operators, or tooling where developers assume that “compiled and simple” automatically means safe.

## How to read these examples

* **Vulnerable snippet** shows the unsafe habit.
* **Safer pattern** shows the direction you want in production code.
* **Why it matters** ties the defect to attacker value and business impact.
* **Review cue** is phrased so it can become a pull-request comment or checklist item.

## Example 1 — SQL injection in database/sql

### Vulnerable snippet

```go
id := r.URL.Query().Get("id")
rows, err := db.Query(fmt.Sprintf("SELECT * FROM users WHERE id = %s", id))
if err != nil { return err }
```

### Safer pattern

```go
id := r.URL.Query().Get("id")
rows, err := db.Query("SELECT * FROM users WHERE id = ?", id)
if err != nil { return err }
```

**Why it matters**

* Formatting SQL strings before sending them to the database merges attacker input into the query itself.

**Business impact**

* Data disclosure, auth bypass, destructive queries, and higher blast radius when service accounts are over-privileged.

**Review cue**

* With `database/sql`, use placeholders and arguments. Ban `fmt.Sprintf` for SQL construction.

## Example 2 — Path traversal in file download handler

### Vulnerable snippet

```go
name := r.URL.Query().Get("name")
path := filepath.Join("/srv/public", name)
http.ServeFile(w, r, path)
```

### Safer pattern

```go
name := r.URL.Query().Get("name")
base := "/srv/public"
clean := filepath.Clean("/" + name)
path := filepath.Join(base, clean)
absBase, _ := filepath.Abs(base)
absPath, _ := filepath.Abs(path)
if !strings.HasPrefix(absPath, absBase+string(os.PathSeparator)) {
    http.Error(w, "invalid path", http.StatusBadRequest)
    return
}
http.ServeFile(w, r, absPath)
```

**Why it matters**

* `filepath.Join` alone is not an authorization boundary; attackers can still reach parent directories if you never prove the final location.

**Business impact**

* Exposure of env files, credentials, kubeconfigs, tokens, or source code from the host.

**Review cue**

* After cleaning and resolving, assert the final path remains under the expected base directory.

## Example 3 — SSRF through arbitrary outbound requests

### Vulnerable snippet

```go
rawURL := r.URL.Query().Get("url")
resp, err := http.Get(rawURL)
if err != nil { return }
defer resp.Body.Close()
```

### Safer pattern

```go
rawURL := r.URL.Query().Get("url")
u, err := url.Parse(rawURL)
if err != nil || u.Scheme != "https" {
    http.Error(w, "bad url", http.StatusBadRequest)
    return
}
allowed := map[string]bool{"status.example.com": true, "cdn.example.com": true}
if !allowed[u.Hostname()] {
    http.Error(w, "destination not allowed", http.StatusForbidden)
    return
}
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(u.String())
if err != nil { return }
defer resp.Body.Close()
```

**Why it matters**

* Server-side fetches inherit the network position and credentials of the service, not of the user who supplied the URL.

**Business impact**

* Cloud metadata exposure, internal API access, reconnaissance, and unexpected use of trusted outbound integrations.

**Review cue**

* Every feature that fetches a URL must define which hosts are allowed and which network ranges are forbidden.

## Example 4 — Command injection with sh -c

### Vulnerable snippet

```go
archive := r.FormValue("archive")
cmd := exec.Command("sh", "-c", "tar -xf "+archive+" -C /srv/import")
_ = cmd.Run()
```

### Safer pattern

```go
archive := r.FormValue("archive")
if strings.Contains(archive, "..") || strings.HasPrefix(archive, "-") {
    http.Error(w, "bad archive name", http.StatusBadRequest)
    return
}
cmd := exec.Command("tar", "-xf", archive, "-C", "/srv/import")
_ = cmd.Run()
```

**Why it matters**

* `sh -c` delegates parsing to a shell, so attacker input can become additional commands or flags.

**Business impact**

* RCE on build/import workers, tampered artifacts, host compromise, and supply-chain evidence corruption.

**Review cue**

* Avoid `sh -c` for request-derived data. Pass fixed commands and validated arguments directly.

## Example 5 — Broken object-level authorization in handler logic

### Vulnerable snippet

```go
invoiceID := chi.URLParam(r, "invoiceID")
row := db.QueryRow("SELECT id, total FROM invoices WHERE id = ?", invoiceID)
// render invoice to currently authenticated user
```

### Safer pattern

```go
invoiceID := chi.URLParam(r, "invoiceID")
userID := auth.UserIDFromContext(r.Context())
row := db.QueryRow(
    "SELECT id, total FROM invoices WHERE id = ? AND owner_user_id = ?",
    invoiceID,
    userID,
)
// if no row, return 404/403
```

**Why it matters**

* Authenticated does not mean authorized. Object IDs without owner/tenant scope create a direct cross-account data path.

**Business impact**

* Data leakage, support incidents, regulatory exposure, and high-severity customer trust failures.

**Review cue**

* Authorization must be checked where the record is fetched, not where a UI route decides what to show.

## Related pages

* [Spring / ASP.NET / Go Security Review Guide](https://github.com/D3One/Product-Security-Gitbook/blob/main/20-stack-specific-secure-engineering/spring-aspnet-and-go-security-review-guide.md)
* [API Testing, Observability, and Release Gates](/architecture-api-crypto-and-identity/index/api-testing-observability-and-release-gates.md)
* [Security Quality Gates and Release Blocking](/devsecops-cicd-and-supply-chain/index-1/security-quality-gates-and-release-blocking.md)

***

*Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.product-security.expert/application-security-and-secure-sdlc/index-4/golang-vulnerability-examples-and-fixes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
