# Go Security Audit

> Go Code Security Audit Module | **Dual-Track Parallel Complete Coverage**
> Applicable to: Go, Gin, Echo, Fiber, net/http, fasthttp, iris, mux, httprouter

---

## Audit Methodology

### Dual-Track Parallel Framework

```
                      Go Code Security Audit
                           │
         ┌─────────────────┼─────────────────┐
         │                 │                 │
         ▼                 ▼                 ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│  Track A (50%)  │ │  Track B (40%)  │ │ Supplement(10%) │
│ Control Modeling│ │  Data Flow      │ │ Config+Dep Audit│
│                 │ │  Analysis       │ │                 │
│ Missing Vulns:  │ │ Injection Vulns:│ │ • Hardcoded     │
│ • Missing Auth  │ │ • SQL Injection │ │   credentials   │
│ • Missing Authz │ │ • Cmd Injection │ │ • Insecure      │
│ • IDOR          │ │ • SSRF          │ │   config        │
│ • Race Cond.    │ │ • Path Traversal│ │ • CVE deps      │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```

### Dual-Track Core Formulas

```
Track A: Missing Vulnerabilities = Sensitive Operations - Required Controls
Track B: Injection Vulnerabilities = Source → [No Sanitization] → Sink
```

**Reference Documents**: `references/core/security_controls_methodology.md`, `references/core/data_flow_methodology.md`

---

# Track A: Control Modeling (Missing Vulnerabilities)

## A1. Sensitive Operations Enumeration

### 1.1 Quick Identification Commands

```bash
# Gin framework routes - data modification operations
grep -rn "\.POST\|\.PUT\|\.DELETE\|\.PATCH" --include="*.go"

# Echo framework routes
grep -rn "e\.POST\|e\.PUT\|e\.DELETE" --include="*.go"

# net/http data modification
grep -rn "case.*POST\|case.*PUT\|case.*DELETE" --include="*.go"

# Data access operations (with parameters)
grep -rn "\.GET.*:\|Param(\|Query(" --include="*.go"

# Batch operations
grep -rn "func.*Export\|func.*Download\|func.*Batch" --include="*.go"

# Financial operations
grep -rn "Transfer\|Payment\|Refund\|Balance" --include="*.go"

# External HTTP requests
grep -rn "http\.Get\|http\.Post\|http\.Client" --include="*.go"

# File operations
grep -rn "os\.Open\|ioutil\.ReadFile\|os\.Create" --include="*.go"

# Command execution
grep -rn "exec\.Command\|os\.StartProcess" --include="*.go"
```

### 1.2 Output Template

```markdown
## Go Sensitive Operations List

| # | Endpoint/Function | HTTP Method | Sensitivity Type | Location | Risk Level |
|---|-------------------|-------------|------------------|----------|------------|
| 1 | /api/user/:id | DELETE | Data Modification | handler.go:45 | High |
| 2 | /api/user/:id | GET | Data Access | handler.go:32 | Medium |
| 3 | /api/transfer | POST | Financial Operation | payment.go:56 | Critical |
```

---

## A2. Security Control Modeling

### 2.1 Go Security Control Implementation

| Control Type | Gin | Echo | Generic Implementation |
|-------------|-----|------|----------------------|
| **Authentication** | JWT middleware | JWT middleware | Custom middleware |
| **Authorization** | Casbin, custom middleware | Casbin | RBAC middleware |
| **Resource Ownership** | Compare in handler | Compare in handler | `user.ID == resource.OwnerID` |
| **Input Validation** | binding, validator | validator | go-playground/validator |
| **Concurrency Control** | GORM locks, DB transactions | Transactions | `SELECT ... FOR UPDATE` |
| **Audit Logging** | Custom middleware | middleware | zap/logrus |

### 2.2 Control Matrix Template (Go)

```yaml
Sensitive Operation: DELETE /api/user/:id
Location: handler.go:45
Type: Data Modification

Required Controls:
  Authentication:
    Requirement: Must be logged in
    Gin: AuthMiddleware()
    Verification: Check if route group applies JWT middleware

  Authorization:
    Requirement: Admin or self
    Implementation: Casbin or custom permission check

  Resource Ownership:
    Requirement: Non-admins can only delete their own data
    Verification: if user.ID != resource.OwnerID { return }
```

---

## A3. Control Existence Verification

### 3.1 Data Modification Operations Verification Checklist

```markdown
## Control Verification: [Endpoint Name]

| Control Item | Required | Code Implementation | Result |
|-------------|----------|---------------------|--------|
| Authentication | Yes | AuthMiddleware | ✅/❌ |
| Authorization | Yes | Casbin/manual check | ✅/❌ |
| Resource Ownership | Yes | OwnerID comparison | ✅/❌ |
| Input Validation | Yes | binding:"required" | ✅/❌ |

### Verification Commands
```bash
# Check route group middleware
grep -B 10 "\.DELETE\|\.POST" [route file] | grep "Use\|middleware"

# Check resource ownership
grep -A 20 "func.*Delete" [handler file] | grep "OwnerID\|UserID\|CreatedBy"
```
```

### 3.2 Common Missing Patterns → Vulnerability Mapping

| Missing Control | Vulnerability Type | CWE | Go Detection Method |
|----------------|-------------------|-----|--------------------|
| No JWT middleware | Missing Authentication | CWE-306 | Check route group Use() |
| No Casbin check | Missing Authorization | CWE-862 | Check handler permission logic |
| No OwnerID check | IDOR | CWE-639 | Check query conditions |
| No FOR UPDATE | Race Condition | CWE-362 | Check financial operation transactions |

---

# Track B: Data Flow Analysis (Injection Vulnerabilities)

> **Core Formula**: Source → [No Sanitization] → Sink = Injection Vulnerability
> **Tool**: gosec static scanning

## B1. Go Source

```go
// net/http
r.URL.Query().Get("name")
r.FormValue("name")
r.Header.Get("X-Header")
r.Cookie("session")

// Gin
c.Query("name")
c.PostForm("name")
c.Param("id")
c.GetHeader("X-Header")
```

## B2. Go Sink

| Sink Type | Vulnerability | Gosec Rule | Dangerous Functions |
|----------|--------------|-----------|-------------------|
| SQL Execution | SQL Injection | G201/G202 | db.Query(sql), fmt.Sprintf |
| Command Execution | Command Injection | G204 | exec.Command("sh", "-c", cmd) |
| File Operations | Path Traversal | G304 | os.Open(userPath) |
| HTTP Request | SSRF | G107 | http.Get(userURL) |

## B3. Gosec Rules and Sink Detection

## Identification Characteristics

```go
// Go project identification
package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

// File structure
├── go.mod
├── go.sum
├── main.go
├── cmd/
├── internal/
│   ├── handler/
│   ├── service/
│   └── repository/
├── pkg/
└── config/
```

---

## Gosec Rule Reference

> gosec detects security issues by scanning Go AST, with rules mapped to CWEs

### G1xx - Credentials and Sensitive Information

| Rule | Description | CWE |
|------|------------|-----|
| G101 | Hardcoded credentials (password, secret, token) | CWE-798 |
| G102 | Binding to all interfaces (0.0.0.0) | CWE-200 |
| G103 | unsafe package usage audit | CWE-242 |
| G104 | Unchecked error return values | CWE-703 |
| G106 | ssh.InsecureIgnoreHostKey usage | CWE-322 |
| G107 | Tainted URL input in HTTP requests | CWE-88 |
| G108 | pprof endpoint auto-exposed (/debug/pprof) | CWE-200 |
| G109 | strconv.Atoi to int16/32 integer overflow | CWE-190 |
| G110 | Decompression bomb DoS | CWE-409 |

### G2xx - Injection

| Rule | Description | CWE |
|------|------------|-----|
| G201 | fmt.Sprintf SQL construction | CWE-89 |
| G202 | String concatenation SQL construction | CWE-89 |
| G203 | HTML template unescaped data | CWE-79 |
| G204 | Command execution audit | CWE-78 |

### G3xx - Files and Paths

| Rule | Description | CWE |
|------|------------|-----|
| G301 | Directory creation with excessive permissions (>0750) | CWE-276 |
| G302 | chmod with excessive permissions | CWE-276 |
| G303 | Predictable path temp file creation | CWE-377 |
| G304 | File path tainted input | CWE-22 |
| G305 | Zip extraction path traversal (Zip Slip) | CWE-22 |
| G306 | File write with excessive permissions | CWE-276 |

### G4xx - Cryptography

| Rule | Description | CWE |
|------|------------|-----|
| G401 | Use of DES/RC4/MD5 | CWE-326 |
| G402 | Insecure TLS configuration | CWE-295 |
| G403 | RSA key < 2048 bits | CWE-326 |
| G404 | Use of math/rand (weak random) | CWE-338 |

### G5xx - Import Blacklist

| Rule | Description |
|------|------------|
| G501 | Import crypto/md5 |
| G502 | Import crypto/des |
| G503 | Import crypto/rc4 |
| G504 | Import net/http/cgi |

---

## Go-Specific Vulnerabilities

### 1. Command Execution (G204)

```go
// Dangerous: user input concatenated into shell
cmd := exec.Command("sh", "-c", userInput)  // RCE!
cmd.Run()

// Dangerous: dynamic command name
cmd := exec.Command(userCmd, userArgs...)  // RCE!

// Dangerous: command parameters from cookie/header
cookie, _ := r.Cookie("cmd")
exec.Command("sh", "-c", cookie.Value)  // RCE!

// Safe: fixed command + whitelist parameters
allowedHosts := map[string]bool{"google.com": true}
if allowedHosts[host] {
    cmd := exec.Command("ping", "-c", "1", host)
}

// Search patterns
exec\.Command|exec\.CommandContext|syscall\.Exec
```

### 2. SQL Injection (G201/G202)

```go
// Dangerous: fmt.Sprintf concatenation (G201)
query := fmt.Sprintf("SELECT * FROM users WHERE id = %s", userID)
db.Query(query)  // SQLi!

// Dangerous: string concatenation (G202)
db.Query("SELECT * FROM users WHERE name = '" + name + "'")

// Dangerous: ORDER BY/LIMIT dynamic concatenation
query := fmt.Sprintf("SELECT * FROM users ORDER BY %s", sortColumn)

// GORM raw SQL
db.Raw("SELECT * FROM users WHERE id = " + id)  // Dangerous!

// Sqlx named query
db.NamedQuery("SELECT * FROM users WHERE name = " + name)  // Dangerous!

// Safe: parameterized queries
db.Query("SELECT * FROM users WHERE id = ?", userID)        // MySQL
db.QueryRow("SELECT * FROM users WHERE id = $1", userID)    // PostgreSQL
db.Raw("SELECT * FROM users WHERE id = ?", id)              // GORM safe usage

// Search patterns
fmt\.Sprintf.*SELECT|fmt\.Sprintf.*INSERT|fmt\.Sprintf.*UPDATE|fmt\.Sprintf.*DELETE
db\.Query.*\+|db\.Exec.*\+|db\.Raw\(.*\+
```

### 3. Template Injection (G203)

```go
// Dangerous: user input as template content
tmpl := template.New("test")
tmpl, _ = tmpl.Parse(userInput)  // SSTI!
tmpl.Execute(w, data)

// Dangerous: text/template (no auto-escaping)
import "text/template"  // More dangerous than html/template

// Dangerous: html/template with escaping disabled
template.HTML(userInput)  // XSS!
template.JS(userInput)    // XSS!
template.CSS(userInput)   // XSS!

// Safe: fixed template + data separation
tmpl := template.Must(template.ParseFiles("template.html"))
tmpl.Execute(w, safeData)

// Search patterns
template\.New.*Parse\(|text/template
template\.HTML\(|template\.JS\(|template\.CSS\(
```

### 4. SSRF (G107)

```go
// Dangerous: user-controllable URL
url := req.FormValue("url")
resp, _ := http.Get(url)  // SSRF!

// Dangerous: unrestricted redirect following
client := &http.Client{}  // Follows redirects by default
resp, _ := client.Get(userURL)

// Dangerous: net.Dial controllable
conn, _ := net.Dial("tcp", userHost+":"+userPort)

// Safe: whitelist + block internal IPs
func isInternalIP(ip net.IP) bool {
    return ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast()
}

parsedURL, _ := url.Parse(userURL)
ips, _ := net.LookupIP(parsedURL.Hostname())
for _, ip := range ips {
    if isInternalIP(ip) {
        return errors.New("internal IP not allowed")
    }
}

// Safe: disable redirect following
client := &http.Client{
    CheckRedirect: func(req *http.Request, via []*http.Request) error {
        return http.ErrUseLastResponse
    },
}

// Protocols that need protection
// file://, gopher://, dict://, ftp://

// Search patterns
http\.Get\(|http\.Post\(|http\.Do\(|http\.NewRequest
net\.Dial|net\.DialTimeout|net\.DialTCP
```

### 5. Path Traversal (G304/G305)

```go
// Dangerous: filepath.Join does NOT prevent path traversal!
filePath := filepath.Join("/uploads", userFilename)
// filepath.Join("/uploads", "../../etc/passwd") = "/etc/passwd"

// Dangerous: Zip extraction path traversal (Zip Slip) (G305)
func extractZip(zipPath, destDir string) {
    r, _ := zip.OpenReader(zipPath)
    for _, f := range r.File {
        path := filepath.Join(destDir, f.Name)  // May escape!
        // f.Name could be "../../../etc/cron.d/malicious"
    }
}

// Safe: verify final path is within target directory
func safeJoin(baseDir, userPath string) (string, error) {
    absBase, _ := filepath.Abs(baseDir)
    targetPath := filepath.Join(absBase, userPath)
    absTarget, _ := filepath.Abs(targetPath)

    if !strings.HasPrefix(absTarget, absBase+string(os.PathSeparator)) {
        return "", errors.New("path traversal detected")
    }
    return absTarget, nil
}

// Search patterns
filepath\.Join|os\.Open|ioutil\.ReadFile|os\.ReadFile|os\.Create
zip\.OpenReader|archive/zip|archive/tar
```

### 6. Integer Overflow (G109)

```go
// Dangerous: strconv.Atoi result cast to smaller type
input := req.FormValue("size")
size, _ := strconv.Atoi(input)
smallSize := int16(size)  // Overflow! 65536 -> 0

// Dangerous: multiplication overflow causing small allocation
count, _ := strconv.Atoi(userInput)
buf := make([]byte, count*elementSize)  // Overflow when count is large

// Safe: bounds checking
size, err := strconv.Atoi(input)
if err != nil || size < 0 || size > math.MaxInt16 {
    return errors.New("invalid size")
}

// Search patterns
strconv\.Atoi.*int16|strconv\.Atoi.*int32
```

### 7. Weak Random Numbers (G404)

```go
// Dangerous: math/rand for security scenarios
import "math/rand"
token := rand.Int()  // Predictable!
rand.Seed(time.Now().UnixNano())  // Seed is guessable

// Safe: crypto/rand
import "crypto/rand"
bytes := make([]byte, 32)
rand.Read(bytes)

// Search patterns
"math/rand"|rand\.Int|rand\.Intn|rand\.Seed
```

### 8. Unsafe Package Abuse (G103)

```go
// Dangerous: unsafe.Pointer conversion
ptr := unsafe.Pointer(&data)
uptr := uintptr(ptr)  // GC may move object during this time
// ... other code ...
newPtr := unsafe.Pointer(uptr)  // May point to invalid memory!

// Dangerous: combined with syscall
syscall.Syscall(SYS_XXX, uintptr(unsafe.Pointer(&buf)), ...)

// Search patterns
unsafe\.Pointer|uintptr\(unsafe
```

### 9. Goroutine Leak

```go
// Dangerous: unbuffered channel blocking
func leak() {
    ch := make(chan int)
    go func() {
        result := doWork()
        ch <- result  // If nobody receives, blocks forever!
    }()

    select {
    case <-time.After(time.Second):
        return  // Timeout return, goroutine leaked
    case r := <-ch:
        return r
    }
}

// Safe: use buffered channel or context cancellation
func safe(ctx context.Context) {
    ch := make(chan int, 1)  // Buffered channel
    go func() {
        select {
        case ch <- doWork():
        case <-ctx.Done():
            return
        }
    }()
}

// Search patterns
make\(chan.*\)|go func\(
```

### 10. pprof Exposure (G108)

```go
// Dangerous: importing pprof auto-registers routes
import _ "net/http/pprof"  // Auto-exposes /debug/pprof

// May leak:
// /debug/pprof/heap     - Memory information
// /debug/pprof/goroutine - Goroutine stacks
// /debug/pprof/cmdline  - Command line arguments

// Safe: separate port or authentication protection
// Do not expose pprof endpoints publicly in production

// Search patterns
net/http/pprof|/debug/pprof
```

### 11. SSH Insecure Configuration (G106)

```go
// Dangerous: ignore host key verification
config := &ssh.ClientConfig{
    HostKeyCallback: ssh.InsecureIgnoreHostKey(),  // Man-in-the-middle attack!
}

// Safe: verify host key
config := &ssh.ClientConfig{
    HostKeyCallback: ssh.FixedHostKey(hostKey),
}

// Search patterns
InsecureIgnoreHostKey
```

### 12. Decompression Bomb (G110)

```go
// Dangerous: no decompression size limit
gzReader, _ := gzip.NewReader(r.Body)
io.Copy(w, gzReader)  // 1KB compressed -> 1GB decompressed = DoS

// Safe: limit read size
limitReader := io.LimitReader(gzReader, maxSize)
io.Copy(w, limitReader)

// Search patterns
gzip\.NewReader|zlib\.NewReader|flate\.NewReader
```

### 13. IPv6 Address Handling

```go
// Dangerous: IPv6 address port concatenation
addr := fmt.Sprintf("%s:%s", host, port)  // IPv6 incorrect!
// "::1:8080" parses incorrectly

// Safe: use net.JoinHostPort
addr := net.JoinHostPort(host, port)  // "[::1]:8080"

// Search patterns
fmt\.Sprintf.*%s:%s.*host|fmt\.Sprintf.*%s:%d.*host
```

### 14. Control Character Injection

```go
// Dangerous: log injection
log.Printf("User: %s", userInput)  // May inject \r\n to forge logs

// Safe: use %q or strconv.Quote
log.Printf("User: %q", userInput)
log.Printf("User: %s", strconv.Quote(userInput))

// Search patterns
log\.Printf.*%s|fmt\.Printf.*%s
```

### 15. JWT/Authentication

```go
// Dangerous: weak key
var jwtKey = []byte("secret")  // Weak!

// Dangerous: no signature algorithm verification
token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
    return jwtKey, nil  // alg not verified, may be bypassed with none algorithm
})

// Safe: strict algorithm verification
token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
    if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
        return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
    }
    return jwtKey, nil
})

// Search patterns
jwt\.Parse|jwt\.ParseWithClaims
jwtKey|secretKey|signingKey
```

### 16. CORS Configuration

```go
// Gin framework - dangerous configuration
r.Use(cors.New(cors.Config{
    AllowOrigins:     []string{"*"},  // Allow all origins
    AllowCredentials: true,           // Dangerous with *!
}))

// Dangerous: reflected Origin
r.Use(cors.New(cors.Config{
    AllowOriginFunc: func(origin string) bool {
        return true  // Reflects any origin
    },
    AllowCredentials: true,
}))

// Search patterns
AllowOrigins|AllowAllOrigins|AllowCredentials|AllowOriginFunc
Access-Control-Allow-Origin
```

---

## Go Audit Checklist

```
Command Execution (G204):
- [ ] Search for exec.Command / exec.CommandContext
- [ ] Check if user input enters command arguments
- [ ] Check for shell mode invocation ("sh", "-c", ...)

SQL Injection (G201/G202):
- [ ] Search for fmt.Sprintf + SQL keywords
- [ ] Search for db.Query/Exec + string concatenation
- [ ] Search for GORM db.Raw() / Sqlx NamedQuery
- [ ] Verify parameterized query usage

Template Injection (G203):
- [ ] Search for template.Parse(user input)
- [ ] Distinguish text/template and html/template
- [ ] Search for template.HTML/JS/CSS

SSRF (G107):
- [ ] Search for http.Get/Post/Do/NewRequest
- [ ] Search for net.Dial/DialTimeout
- [ ] Check URL whitelist validation
- [ ] Check redirect handling

File Operations (G304/G305):
- [ ] Search for filepath.Join + user input
- [ ] Verify path traversal protection
- [ ] Check zip/tar extraction safety

Integer Overflow (G109):
- [ ] Search for strconv.Atoi cast to small integer types
- [ ] Check multiplication/addition overflow

Weak Random (G404):
- [ ] Search for math/rand in security scenarios
- [ ] Verify crypto/rand usage

Authentication & Authorization:
- [ ] Check JWT key strength and algorithm verification
- [ ] Check CORS configuration
- [ ] Audit middleware authentication

Sensitive Information (G101):
- [ ] Search for hardcoded passwords/keys/tokens
- [ ] Check if logs record sensitive information
- [ ] Check pprof endpoint exposure (G108)

Resource Safety:
- [ ] Check for goroutine leaks
- [ ] Check decompression size limits (G110)
- [ ] Check error handling (G104)
```

---

## Audit Regular Expressions

```regex
# Command Execution (G204)
exec\.Command|exec\.CommandContext|syscall\.Exec

# SQL Injection (G201/G202)
fmt\.Sprintf.*(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE)
db\.(Query|Exec|Raw)\s*\([^)]*\+
NamedQuery\s*\([^)]*\+

# Template Injection (G203)
template\.New.*Parse\(|text/template
template\.(HTML|JS|CSS)\s*\(

# SSRF (G107)
http\.(Get|Post|Do|NewRequest)\s*\(
net\.(Dial|DialTimeout|DialTCP)\s*\(

# Path Traversal (G304/G305)
filepath\.Join|os\.(Open|Create|ReadFile)|ioutil\.ReadFile
zip\.OpenReader|archive/(zip|tar)

# Integer Overflow (G109)
strconv\.Atoi.*int(8|16|32)

# Weak Random (G404)
"math/rand"|rand\.(Int|Intn|Seed)

# Hardcoded Credentials (G101)
(password|passwd|secret|token|apikey|api_key)\s*[:=]\s*["'][^"']+["']

# pprof Exposure (G108)
net/http/pprof|/debug/pprof

# SSH Insecure (G106)
InsecureIgnoreHostKey

# unsafe Usage (G103)
unsafe\.Pointer|uintptr\(unsafe

# Decompression (G110)
gzip\.NewReader|zlib\.NewReader|flate\.NewReader
```

---

## Audit Tools

```bash
# Gosec - Go security checker
go install github.com/securego/gosec/v2/cmd/gosec@latest
gosec ./...
gosec -severity medium ./...
gosec -include=G101,G201,G204 ./...
gosec -exclude=G104 ./...
gosec -fmt=json -out=results.json ./...

# Configure G101 rule
cat > gosec.json << 'EOF'
{
  "G101": {
    "pattern": "(?i)passwd|pass|password|pwd|secret|private_key|token|apikey",
    "ignore_entropy": false,
    "entropy_threshold": "80.0"
  }
}
EOF
gosec -conf=gosec.json ./...

# Other tools
go vet ./...                    # Built-in static analysis
staticcheck ./...               # Deep checks
golangci-lint run               # Comprehensive linter

# CodeQL for Go
# 1. Create qlpack.yml config file
cat > qlpack.yml << 'EOF'
name: your-org/codeql-go-queries
version: 0.0.1
libraryPathDependencies: codeql-go
extractor: go
EOF

# 2. Create CodeQL database
codeql database create ./codeql_database -s /path/to/go/project --language=go

# 3. Run queries
codeql database analyze ./codeql_database codeql/go-queries --format=sarif-latest --output=results.sarif

# CodeQL Go standard library reference
# https://codeql.github.com/codeql-standard-libraries/go/
```

---

## Minimal PoC Examples
```bash
# SSRF
curl "http://localhost:8080/fetch?url=http://169.254.169.254/latest/meta-data/"

# Path Traversal
curl "http://localhost:8080/download?file=../../etc/passwd"

# Command Injection
curl "http://localhost:8080/ping?host=google.com;id"
```

---

---

## Authorization Vulnerability Detection (Authorization Gap) - v1.7.1

> **Core Issue**: Authorization vulnerabilities are "missing code" -- grep cannot detect "code that should exist but doesn't"
> **Solution**: Authorization matrix approach - start from "what should be" rather than "what exists"

### Methodology

```
Old Approach (Passive Detection - Limited):
   Search middleware calls → check if they exist
   Problem: existing middleware does not mean correct; may be misconfigured or incomplete

New Approach (Active Modeling - Systematic):
   1. Enumerate all sensitive operations (DELETE/PUT handler)
   2. Define required permissions (who can do what)
   3. Compare actual code, detect missing or inconsistent controls
```

### Gin Framework Authorization Detection

```bash
# Step 1: Find all sensitive routes
grep -rn "\.DELETE\|\.PUT\|\.PATCH" --include="*.go"
grep -rn "func.*Delete\|func.*Update\|func.*Remove" --include="*.go"

# Step 2: Check if route group has authentication middleware
grep -rn "\.Group" --include="*.go" -A 5 | grep -E "AuthMiddleware|JWTAuth|RequireAuth"

# Step 3: Check if specific handler has permission checks
grep -rn "func.*Delete" --include="*.go" -A 20 | grep -E "userID|ownerID|CheckPermission|Authorize"
```

### Vulnerability Patterns

```go
// Vulnerable: delete handler missing permission check
func DeleteFile(c *gin.Context) {
    fileID := c.Param("id")
    // No check if user has permission to delete this file
    db.Delete(&File{}, fileID)
    c.JSON(200, gin.H{"status": "deleted"})
}

// Vulnerable: authentication but no authorization (horizontal privilege escalation)
func DeleteFile(c *gin.Context) {
    fileID := c.Param("id")
    userID := c.GetInt("userID")  // Get user ID from JWT
    // Only verifies login, not whether user is the file owner
    db.Delete(&File{}, fileID)  // Can delete others' files!
    c.JSON(200, gin.H{"status": "deleted"})
}

// Safe: authentication + authorization + resource ownership verification
func DeleteFile(c *gin.Context) {
    fileID := c.Param("id")
    userID := c.GetInt("userID")

    // Verify resource ownership
    var file File
    if err := db.Where("id = ? AND owner_id = ?", fileID, userID).First(&file).Error; err != nil {
        c.JSON(403, gin.H{"error": "not authorized"})
        return
    }

    db.Delete(&file)
    c.JSON(200, gin.H{"status": "deleted"})
}
```

### Echo Framework Authorization Detection

```bash
# Check route definitions
grep -rn "\.DELETE\|\.PUT\|\.PATCH" --include="*.go"

# Check middleware configuration
grep -rn "e\.Use\|g\.Use" --include="*.go" -A 2 | grep -E "middleware\.|JWT|Auth"
```

### Vulnerability Patterns (Echo)

```go
// Vulnerable: route group has auth but no fine-grained authorization
api := e.Group("/api", middleware.JWT([]byte("secret")))
api.DELETE("/users/:id", deleteUser)  // Any logged-in user can delete any user!

// Safe: add permission middleware
api := e.Group("/api", middleware.JWT([]byte("secret")))
admin := api.Group("/admin", AdminOnly)
admin.DELETE("/users/:id", deleteUser)  // Only admins can delete
```

### Fiber Framework Authorization Detection

```bash
# Check route definitions
grep -rn "\.Delete\|\.Put\|\.Patch" --include="*.go"

# Check middleware
grep -rn "app\.Use\|group\.Use" --include="*.go" -A 2
```

### Authorization Consistency Detection Script

```bash
#!/bin/bash
# check_auth_consistency_go.sh

echo "=== Go Authorization Consistency Check ==="

# Find all Go files
GO_FILES=$(find . -name "*.go" -type f)

for gofile in $GO_FILES; do
    # Check for sensitive routes
    DELETE_ROUTES=$(grep -n "\.DELETE\|\.Delete" "$gofile" 2>/dev/null)
    PUT_ROUTES=$(grep -n "\.PUT\|\.Put" "$gofile" 2>/dev/null)

    if [ -n "$DELETE_ROUTES" ] || [ -n "$PUT_ROUTES" ]; then
        echo ""
        echo "Checking: $gofile"

        # Check for authentication middleware
        AUTH_MIDDLEWARE=$(grep -c "AuthMiddleware\|JWTMiddleware\|RequireAuth\|middleware\.JWT" "$gofile")

        if [ "$AUTH_MIDDLEWARE" -eq 0 ]; then
            echo "  ⚠️  Sensitive routes found without authentication middleware"
        fi

        # Check for permission verification in handler
        echo "$DELETE_ROUTES" | while read line; do
            if [ -n "$line" ]; then
                handler=$(echo "$line" | grep -o "[A-Za-z]*Delete[A-Za-z]*\|delete[A-Za-z]*")
                if [ -n "$handler" ]; then
                    # Check handler implementation
                    has_owner_check=$(grep -A 30 "func.*$handler" "$gofile" | grep -c "owner_id\|OwnerID\|user_id.*=\|UserID.*=")
                    if [ "$has_owner_check" -eq 0 ]; then
                        echo "  ⚠️  $handler: may be missing resource ownership verification"
                    fi
                fi
            fi
        done
    fi
done
```

### Indirect SSRF Detection (Configuration-Driven)

```go
// Vulnerable: configuration-driven indirect SSRF
type Config struct {
    APIBaseURL string `yaml:"api_base_url"`
}

func FetchData(cfg *Config, endpoint string) ([]byte, error) {
    url := cfg.APIBaseURL + endpoint  // Indirect SSRF
    resp, err := http.Get(url)
    // ...
}

// Detection commands
grep -rn "viper\.Get.*URL\|viper\.Get.*Host\|config\.\w*URL" --include="*.go"
grep -rn "os\.Getenv.*URL\|os\.Getenv.*HOST" --include="*.go"
grep -rn "fmt\.Sprintf.*%s.*http\|fmt\.Sprintf.*http.*%s" --include="*.go"
```

### Audit Checklist (Authorization Focus)

```
Authorization Matrix Modeling:
- [ ] List all sensitive routes (DELETE/PUT/PATCH)
- [ ] Define expected permissions for each route
- [ ] Check actual middleware configuration matches expectations

Gin/Echo/Fiber Specific:
- [ ] Check route group middleware configuration
- [ ] Verify DELETE routes have authentication middleware
- [ ] Check resource ownership verification in handlers

Horizontal Privilege Escalation Protection:
- [ ] Verify all resource operations check owner_id/user_id
- [ ] Check if database queries include user filter conditions
- [ ] Verify permission checks for batch operations

Middleware Configuration:
- [ ] Check middleware order (authentication → authorization)
- [ ] Verify JWT key strength
- [ ] Check CORS configuration

Indirect Injection:
- [ ] Check URL configuration in viper/config
- [ ] Track controllable values in environment variables
- [ ] Verify URLs constructed with fmt.Sprintf
```

---

## CSRF Protection (CWE-352)

### Dangerous Patterns

```go
// Gin - No CSRF protection
r := gin.Default()
r.POST("/api/transfer", func(c *gin.Context) {
    // State-changing operation without CSRF protection
    var req TransferRequest
    c.BindJSON(&req)
    transfer(req.To, req.Amount)
})
```

### Safe Configuration

```go
// Gin + gorilla/csrf
import (
    "github.com/gorilla/csrf"
    adapter "github.com/gwatts/gin-adapter"
)

func main() {
    r := gin.Default()

    // CSRF middleware
    csrfMiddleware := csrf.Protect(
        []byte("32-byte-long-auth-key-here!!!!!"),
        csrf.Secure(true),  // HTTPS only
        csrf.HttpOnly(true),
    )

    r.Use(adapter.Wrap(csrfMiddleware))

    r.GET("/form", func(c *gin.Context) {
        token := csrf.Token(c.Request)
        c.HTML(200, "form.html", gin.H{"csrf": token})
    })

    r.POST("/api/transfer", func(c *gin.Context) {
        // CSRF token auto-verified
        var req TransferRequest
        c.BindJSON(&req)
        transfer(req.To, req.Amount)
    })
}

// Echo + middleware
import "github.com/labstack/echo/v4/middleware"

e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
    TokenLookup: "header:X-CSRF-Token",
    CookieName:  "_csrf",
    CookieSecure: true,
}))
```

### Detection Commands

```bash
# Find POST/PUT/DELETE routes
rg -n '\.(POST|PUT|DELETE|PATCH)\(' --glob "*.go"

# Find projects missing CSRF middleware
rg -n "csrf|CSRF" --glob "*.go" || echo "No CSRF protection found"
```

---

## File Upload Security (CWE-434)

### Dangerous Patterns

```go
// Unvalidated file upload
func uploadHandler(c *gin.Context) {
    file, _ := c.FormFile("file")
    c.SaveUploadedFile(file, "/uploads/"+file.Filename)  // Path traversal + arbitrary type
}
```

### Safe Configuration

```go
import (
    "path/filepath"
    "strings"
    "github.com/h2non/filetype"
)

var allowedTypes = map[string]bool{
    "image/jpeg": true,
    "image/png":  true,
    "image/gif":  true,
}

const maxFileSize = 5 * 1024 * 1024  // 5MB

func uploadHandler(c *gin.Context) {
    file, header, err := c.Request.FormFile("file")
    if err != nil {
        c.JSON(400, gin.H{"error": "No file"})
        return
    }
    defer file.Close()

    // 1. Size limit
    if header.Size > maxFileSize {
        c.JSON(400, gin.H{"error": "File too large"})
        return
    }

    // 2. Read file header to determine real type
    head := make([]byte, 261)
    file.Read(head)
    file.Seek(0, 0)

    kind, _ := filetype.Match(head)
    if !allowedTypes[kind.MIME.Value] {
        c.JSON(400, gin.H{"error": "Invalid file type"})
        return
    }

    // 3. Safe filename
    ext := filepath.Ext(header.Filename)
    if !isAllowedExt(ext) {
        c.JSON(400, gin.H{"error": "Invalid extension"})
        return
    }
    safeName := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)

    // 4. Safe path
    uploadDir := "/uploads"
    dst := filepath.Join(uploadDir, safeName)
    if !strings.HasPrefix(filepath.Clean(dst), uploadDir) {
        c.JSON(400, gin.H{"error": "Invalid path"})
        return
    }

    out, _ := os.Create(dst)
    defer out.Close()
    io.Copy(out, file)

    c.JSON(200, gin.H{"filename": safeName})
}

func isAllowedExt(ext string) bool {
    allowed := []string{".jpg", ".jpeg", ".png", ".gif"}
    ext = strings.ToLower(ext)
    for _, a := range allowed {
        if ext == a {
            return true
        }
    }
    return false
}
```

### Detection Commands

```bash
# Find file uploads
rg -n "FormFile|SaveUploadedFile|MultipartForm" --glob "*.go"

# Find uploads missing validation
rg -A10 "FormFile" --glob "*.go" | grep -v "filetype\|MIME\|extension"
```

---

## References

- [gosec GitHub](https://github.com/securego/gosec)
- [Go Security Best Practices](https://go.dev/doc/security)
- [OWASP Go Security Guide](https://owasp.org/www-project-web-security-testing-guide/)
