| name | golang-security-guide |
| description | Reference knowledge base for the go-security-audit agent. Loaded by that agent on its first iteration when the host has not already injected it; not intended for direct invocation. |
Go Security: Comprehensive Guide to Identifying and Patching Vulnerabilities
Table of Contents
- Introduction
- Security Tools and Analysis
- Common Vulnerabilities
- Memory Safety and Overflow Vulnerabilities
- gRPC Security
- Cryptography Best Practices
- Concurrency and Race Conditions
- Dependency Security and Supply Chain
- Security Checklist
Introduction
Go is designed with security in mind, featuring built-in memory safety, garbage collection, and strong typing. However, vulnerabilities can still occur through improper use of language features, dependencies, or external integrations. In 2026, there have been 9 vulnerabilities in Go with an average score of 6.5 out of ten.
Key Security Principles
- Keep Go updated (security fixes issued to the two most recent major releases)
- Use official security tools (govulncheck, gosec, go vet)
- Validate and sanitize all user input
- Minimize dependency tree
- Never execute untrusted code during build/fetch
- Follow secure coding practices for your domain
Security Tools and Analysis
1. govulncheck - Official Vulnerability Scanner
govulncheck is backed by the Go vulnerability database and analyzes your codebase to surface only vulnerabilities that actually affect you, based on which functions in your code are transitively calling vulnerable functions.
Installation:
go install golang.org/x/vuln/cmd/govulncheck@latest
Usage:
govulncheck ./...
govulncheck ./pkg/...
CI/CD Integration:
- GitHub Action available on GitHub Marketplace
- Can be integrated into any CI/CD pipeline
- VS Code Go extension checks dependencies and surfaces vulnerabilities
Resources:
2. gosec - Static Analysis Security Tool
gosec scans Go code for security problems by inspecting the AST (Abstract Syntax Tree) and matching against security rules.
Installation:
go install github.com/securego/gosec/v2/cmd/gosec@latest
Usage:
gosec ./...
gosec -fmt=json -out=results.json ./...
gosec -include=G401,G501 ./...
Key Features:
- Maps issues to CWE (Common Weakness Enumeration)
- Multiple output formats (text, JSON, SARIF)
- Configurable rules and severity filtering
- Supports exclusion of directories/packages
Common Security Checks:
- Hard-coded credentials (G101, G102)
- SQL injection vulnerabilities (G201, G202)
- Weak cryptographic algorithms (G401, G501, G502)
- Insecure usage of os/exec (G204)
- File permissions and path traversal (G301-G306)
- Use of unsafe package (G103)
Limitations:
- Only static analysis (cannot detect runtime vulnerabilities)
- Should be complemented with dynamic analysis and manual reviews
Resources:
3. go vet - Built-in Code Analysis
go vet examines Go source code and reports suspicious constructs that might lead to runtime problems.
Usage:
go vet
go vet ./pkg/...
go vet -race ./...
What it catches:
- Unreachable code
- Unused variables
- Common mistakes with goroutines
- Printf-family functions with wrong arguments
- Suspicious constructs
4. Additional Security Tools
staticcheck:
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck ./...
golangci-lint (aggregates multiple linters):
golangci-lint run
osv-scanner (Google's vulnerability scanner):
go install github.com/google/osv-scanner/cmd/osv-scanner@latest
osv-scanner --lockfile=go.mod
Common Vulnerabilities
1. Injection Attacks
SQL Injection
Vulnerability:
Occurs when untrusted data is sent to an interpreter as part of a command or query.
Vulnerable Code:
query := fmt.Sprintf("SELECT * FROM users WHERE username='%s'", username)
rows, err := db.Query(query)
Secure Code:
query := "SELECT * FROM users WHERE username=$1"
rows, err := db.Query(query, username)
stmt, err := db.Prepare("SELECT * FROM users WHERE username=?")
if err != nil {
return err
}
defer stmt.Close()
rows, err := stmt.Query(username)
Key Points:
- SQL parameter values as function arguments prevent injection
- Use
database/sql package's parameterized query methods
- Placeholder format varies by driver (?, $1, etc.)
- Parameterized queries guarantee proper escaping
Resources:
Command Injection
Vulnerability:
Untrusted input passed directly to system shell allows arbitrary command execution.
Vulnerable Code:
cmd := exec.Command("/bin/sh", "-c", "ls "+userInput)
cmd := exec.Command("bash", "-c", "myCommand "+userInput)
Secure Code:
cmd := exec.Command("/path/to/myCommand", "myArg1", inputValue)
allowedCommands := map[string]bool{
"list": true,
"status": true,
}
if !allowedCommands[userInput] {
return errors.New("invalid command")
}
cmd := exec.Command("/bin/sh", "-c", userInput)
cmd := exec.Command("/bin/ls", "-la", filepath.Clean(userPath))
Prevention Strategies:
- Use parameterization instead of string concatenation
- Avoid shell invocation when possible (Go lacks proper shell-escaping)
- Use allowlists for permitted commands
- Validate and sanitize all user inputs
Resources:
2. Cross-Site Scripting (XSS)
Vulnerability:
User-generated content executed as JavaScript or HTML in browsers.
Vulnerable Code:
import "text/template"
tmpl := template.Must(template.New("page").Parse(`
<div>{{.UserContent}}</div>
`))
tmpl.Execute(w, data)
io.WriteString(w, "<div>"+userContent+"</div>")
Secure Code:
import "html/template"
tmpl := template.Must(template.New("page").Parse(`
<div>{{.UserContent}}</div>
`))
tmpl.Execute(w, data)
Contextual Auto-Escaping:
template := `
<script>
var data = {{.JSData}}; // JavaScript context
</script>
<div class="{{.CSSClass}}"> // CSS context
<a href="{{.URL}}">{{.Text}}</a> // URL and HTML context
</div>
`
Dangerous Types to AVOID:
template.HTML
template.HTMLAttr
template.JS
template.URL
template.CSS
Best Practices:
- Always use
html/template, NEVER text/template for HTML output
- Ban dangerous bypass types in code reviews
- Set appropriate Content-Type headers
- Never write user content directly to response without template engine
Resources:
3. Path Traversal
Vulnerability:
Attackers control file system access through manipulated file paths.
Vulnerable Code:
filepath := "/var/www/files/" + userInput
content, err := ioutil.ReadFile(filepath)
Secure Code (Go 1.20+):
import "path/filepath"
basePath := "/var/www/files"
requestedFile := filepath.Clean(userInput)
fullPath := filepath.Join(basePath, requestedFile)
if !strings.HasPrefix(fullPath, filepath.Clean(basePath)+string(os.PathSeparator)) {
return errors.New("invalid path")
}
if !filepath.IsLocal(userInput) {
return errors.New("path escapes directory")
}
fullPath := filepath.Join(basePath, userInput)
content, err := os.ReadFile(fullPath)
Secure Code (Go 1.24+):
root := os.Root("/var/www/files")
content, err := root.ReadFile(userInput)
Critical Vulnerability (CVE-2022-41722):
On Windows, filepath.Clean could transform invalid paths like "a/../c:/b" into valid path "c:\b", enabling directory traversal. Fixed in Go 1.19.6 and 1.20.1.
Best Practices:
- Always validate and clean user-supplied file paths
- Use
filepath.Join and filepath.Clean together
- Verify final path stays within expected directory
- Consider
filepath.IsLocal (Go 1.20+) or os.Root (Go 1.24+)
- Never trust user input for file operations
Resources:
Memory Safety and Overflow Vulnerabilities
1. Buffer Overflow
Overview:
Go is generally memory-safe with built-in bounds checking, preventing traditional buffer overflow vulnerabilities common in C/C++. However, vulnerabilities can still occur.
Go's Protection Mechanisms:
- Bounds-checked arrays and slices
- No dangling pointers
- Garbage collection
- Automatic memory management
Known CVEs:
- CVE-2022-24675: Buffer overflow via large arguments in WASM function invocation (Go < 1.16.9, 1.17.2)
- CVE-2021-38297: Decode stack overflow via large PEM data in encoding/pem (Go < 1.17.9, 1.18.1)
Bounds Checking in Go:
arr := []int{1, 2, 3, 4, 5}
value := arr[10]
if index < len(arr) && index >= 0 {
value := arr[index]
}
Bounds Check Elimination (BCE):
Go compiler can optimize away redundant bounds checks when it can prove safety.
if len(slice) >= 4 {
_ = slice[3]
a := slice[0]
b := slice[1]
c := slice[2]
d := slice[3]
}
Resources:
2. Integer Overflow and Underflow
Vulnerability:
Go doesn't check for integer overflow, similar to C, C++, and Java. Operations wrap around silently.
Behavior:
- Unsigned integers: operations computed modulo 2^n upon overflow
- Signed integers: computed using two's complement arithmetic, truncated to bit width
- No exception raised on overflow
Vulnerable Code:
var x uint8 = 255
x = x + 1
size := userInput1 * userInput2
buffer := make([]byte, size)
offset := baseAddr + userOffset
ptr := unsafe.Pointer(offset)
Security Implications:
- Programs making system calls may pass corrupted data structures to kernel
- Marshaled data sent over network may be silently corrupted
- Programs using
unsafe are vulnerable to same bugs as C
- Bounds-checking on slices mitigates some but not all harmful effects
Secure Code:
func SafeAdd(a, b uint32) (uint32, error) {
if a > math.MaxUint32 - b {
return 0, errors.New("integer overflow")
}
return a + b, nil
}
func SafeMultiply(a, b uint32) (uint32, error) {
if a != 0 && b > math.MaxUint32/a {
return 0, errors.New("integer overflow")
}
return a * b, nil
}
import "math/big"
bigA := big.NewInt(9223372036854775807)
bigB := big.NewInt(9223372036854775807)
result := new(big.Int).Add(bigA, bigB)
Known Vulnerability (CVE):
Integer overflow in crypto/elliptic allows DoS via specially crafted scalar input > 32 bytes to P256().ScalarMult or P256().ScalarBaseMult.
Resources:
3. The unsafe Package
Risk Level: CRITICAL
The unsafe package allows programs to defeat the type system and bypass Go's memory safety guarantees.
Dangers:
- Defeats memory safety
- Can read/write arbitrary memory
- No compiler enforcement of safety
- Combined with user data, can enable attackers to break memory safety
Common Use Cases (and risks):
import "unsafe"
ptr := unsafe.Pointer(&someVar)
ptr = unsafe.Pointer(uintptr(ptr) + offset)
var f float64 = 3.14
bits := *(*uint64)(unsafe.Pointer(&f))
size := unsafe.Sizeof(someStruct)
CGO Risks:
When combining unsafe with CGO:
- Memory Leaks: Passing unsafe.Pointer to C functions can leak memory
- Garbage Collection Issues: Go may GC or move pointers actively used by C
- Pointer Passing Rules:
- Cannot store Go pointer to unpinned memory in C memory
- Go functions called by C must ensure Go memory remains pinned
- Manual Memory Management: C.CString() allocates C memory that must be manually freed
Safer CGO Alternative:
import "runtime/cgo"
h := cgo.NewHandle(goValue)
defer h.Delete()
Data Races Breaking Memory Safety:
Data races can break Go's memory safety guarantees even without unsafe.
Best Practices:
- Avoid
unsafe unless absolutely necessary
- Thoroughly audit all
unsafe usage
- Never use
unsafe with user-controlled data
- Use
cgo.Handle for Go-C interop
- Run with race detector during testing
- Document and justify every use of
unsafe
Resources:
gRPC Security
1. Common gRPC Vulnerabilities
Plaintext Communication (CRITICAL)
Vulnerability:
gRPC servers by default allow plaintext communication, exposing data to eavesdropping and tampering.
Vulnerable Code:
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
lis, err := net.Listen("tcp", ":50051")
grpcServer := grpc.NewServer()
grpcServer.Serve(lis)
Secure Code:
creds, err := credentials.NewClientTLSFromFile("server.crt", "")
if err != nil {
log.Fatal(err)
}
conn, err := grpc.Dial("localhost:50051",
grpc.WithTransportCredentials(creds))
creds, err := credentials.NewServerTLSFromFile("server.crt", "server.key")
if err != nil {
log.Fatal(err)
}
grpcServer := grpc.NewServer(grpc.Creds(creds))
Resources:
HTTP/2 Rapid Reset Attack (CVE-2023-44487)
Vulnerability:
Attackers send and cancel HTTP/2 requests rapidly, causing excessive concurrent method handlers and resource exhaustion.
Vulnerable Code:
grpcServer := grpc.NewServer()
Secure Code:
grpcServer := grpc.NewServer(
grpc.MaxConcurrentStreams(100),
)
Resources:
Denial of Service via Large Messages
Vulnerability:
Arbitrarily large messages can exhaust server memory.
Secure Code:
conn, err := grpc.Dial("localhost:50051",
grpc.WithTransportCredentials(creds),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(4*1024*1024),
grpc.MaxCallSendMsgSize(4*1024*1024),
),
)
grpcServer := grpc.NewServer(
grpc.MaxRecvMsgSize(4*1024*1024),
grpc.MaxSendMsgSize(4*1024*1024),
grpc.MaxConcurrentStreams(100),
)
2. Authentication and Authorization
Token-Based Authentication
import (
"context"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/credentials"
)
func (t *tokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"authorization": "Bearer " + t.token,
}, nil
}
func (t *tokenAuth) RequireTransportSecurity() bool {
return true
}
perRPC := &tokenAuth{token: "your-jwt-token"}
conn, err := grpc.Dial("localhost:50051",
grpc.WithTransportCredentials(creds),
grpc.WithPerRPCCredentials(perRPC),
)
func authenticateToken(ctx context.Context) error {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return errors.New("missing metadata")
}
tokens := md["authorization"]
if len(tokens) == 0 {
return errors.New("missing token")
}
token := strings.TrimPrefix(tokens[0], "Bearer ")
if !validateToken(token) {
return errors.New("invalid token")
}
return nil
}
func authInterceptor(ctx context.Context, req interface{},
info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
if err := authenticateToken(ctx); err != nil {
return nil, status.Error(codes.Unauthenticated, err.Error())
}
return handler(ctx, req)
}
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(authInterceptor),
)
Mutual TLS (mTLS)
cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
log.Fatal(err)
}
certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile("ca.crt")
if err != nil {
log.Fatal(err)
}
certPool.AppendCertsFromPEM(ca)
creds := credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: certPool,
})
grpcServer := grpc.NewServer(grpc.Creds(creds))
cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
log.Fatal(err)
}
certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile("ca.crt")
if err != nil {
log.Fatal(err)
}
certPool.AppendCertsFromPEM(ca)
creds := credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: certPool,
})
conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(creds))
Resources:
3. Input Validation with Protovalidate
Modern Approach (Recommended):
Proto Definition:
syntax = "proto3";
import "buf/validate/validate.proto";
message User {
string email = 1 [(buf.validate.field).string.email = true];
string username = 2 [
(buf.validate.field).string = {
min_len: 3,
max_len: 30,
pattern: "^[a-zA-Z0-9_]+$"
}
];
int32 age = 3 [
(buf.validate.field).int32 = {
gte: 0,
lte: 150
}
];
}
Server Implementation:
import (
"context"
"github.com/bufbuild/protovalidate-go"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func validationInterceptor(ctx context.Context, req interface{},
info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
validator, err := protovalidate.New()
if err != nil {
return nil, status.Error(codes.Internal, "validation setup failed")
}
if msg, ok := req.(proto.Message); ok {
if err := validator.Validate(msg); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
}
return handler(ctx, req)
}
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(validationInterceptor),
)
Legacy Approach:
import (
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_validator "github.com/grpc-ecosystem/go-grpc-middleware/validator"
)
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(
grpc_middleware.ChainUnaryServer(
grpc_validator.UnaryServerInterceptor(),
),
),
)
Resources:
4. Rate Limiting
Interceptor-Based Rate Limiting:
import (
"context"
"golang.org/x/time/rate"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"sync"
)
type rateLimiter struct {
limiters map[string]*rate.Limiter
mu sync.RWMutex
rate rate.Limit
burst int
}
func newRateLimiter(r rate.Limit, b int) *rateLimiter {
return &rateLimiter{
limiters: make(map[string]*rate.Limiter),
rate: r,
burst: b,
}
}
func (rl *rateLimiter) getLimiter(key string) *rate.Limiter {
rl.mu.Lock()
defer rl.mu.Unlock()
limiter, exists := rl.limiters[key]
if !exists {
limiter = rate.NewLimiter(rl.rate, rl.burst)
rl.limiters[key] = limiter
}
return limiter
}
func (rl *rateLimiter) unaryInterceptor(ctx context.Context, req interface{},
info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
clientIP := getClientIP(ctx)
limiter := rl.getLimiter(clientIP)
if !limiter.Allow() {
return nil, status.Error(codes.ResourceExhausted, "rate limit exceeded")
}
return handler(ctx, req)
}
rl := newRateLimiter(rate.Limit(10), 20)
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(rl.unaryInterceptor),
)
Resources:
5. gRPC Security Checklist
Resources:
Cryptography Best Practices
1. Use Strong Algorithms
AVOID (Weak/Deprecated):
- MD5 (broken)
- SHA-1 (deprecated)
- RC4 (insecure)
- DES, 3DES (weak)
- RSA < 2048 bits
USE (Secure):
- SHA-256, SHA-512 (hashing)
- AES-256 (encryption)
- RSA >= 2048 bits (preferably 4096)
- ECDSA with P-256 or higher
- Ed25519 (signing)
- Argon2, bcrypt, scrypt (password hashing)
2. Secure Encryption Example
AES-GCM (Authenticated Encryption):
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
)
func encrypt(plaintext []byte, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
}
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
return ciphertext, nil
}
func decrypt(ciphertext []byte, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, errors.New("ciphertext too short")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}
return plaintext, nil
}
3. Key Generation
Generate Cryptographically Secure Keys:
import "crypto/rand"
func generateKey(size int) ([]byte, error) {
key := make([]byte, size)
_, err := rand.Read(key)
if err != nil {
return nil, err
}
return key, nil
}
4. Password Hashing
Use bcrypt or Argon2:
import "golang.org/x/crypto/bcrypt"
func hashPassword(password string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(password), 12)
if err != nil {
return "", err
}
return string(hash), nil
}
func verifyPassword(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
5. Cryptography Audit
In 2024, Google contracted Trail of Bits for an independent security audit of Go's core cryptography packages. The audit covered:
- Key exchange (ECDH, ML-KEM)
- Digital signatures (ECDSA, RSA, Ed25519)
- Encryption (AES-GCM, AES-CBC, AES-CTR)
- Hashing (SHA-1, SHA-2, SHA-3)
- Key derivation (HKDF, PBKDF2)
- Authentication (HMAC)
Result: One low-severity finding in legacy Go+BoringCrypto integration.
Resources:
Concurrency and Race Conditions
1. Data Races
What is a Data Race?
A data race occurs when two goroutines access the same variable concurrently and at least one access is a write.
Security Implications:
- Can break Go's memory safety guarantees
- Unauthorized access or modification of data
- Denial of service
- Privilege escalation
- Unpredictable behavior
Vulnerable Code:
package main
var counter int
func increment() {
counter++
}
func main() {
for i := 0; i < 1000; i++ {
go increment()
}
}
2. Detection with Race Detector
Usage:
go test -race ./...
go run -race main.go
go build -race
Limitations:
- Only works on 64-bit systems
- Only detects data races (not race conditions)
- Requires the race to actually occur during execution
- Cannot detect race conditions (logical bugs)
3. Solutions
Solution 1: Channels (Preferred in Go)
package main
func increment(counter chan int) {
for {
count := <-counter
count++
counter <- count
}
}
func main() {
counter := make(chan int, 1)
counter <- 0
go increment(counter)
counter <- <-counter + 1
}
Solution 2: Mutex
import "sync"
type SafeCounter struct {
mu sync.Mutex
value int
}
func (c *SafeCounter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *SafeCounter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
Solution 3: Atomic Operations
import "sync/atomic"
var counter int64
func increment() {
atomic.AddInt64(&counter, 1)
}
func value() int64 {
return atomic.LoadInt64(&counter)
}
4. Best Practices
- Share memory by communicating (use channels)
- Don't communicate by sharing memory (avoid shared state)
- Always run tests with
-race flag
- Use mutexes when you must share memory
- Use atomic operations for simple counters/flags
- Design concurrent code to minimize shared state
- Document which goroutines access which data
Resources:
Dependency Security and Supply Chain
1. How Go Mitigates Supply Chain Attacks
go.sum File:
Contains cryptographic hashes (SHA-256) of each dependency, ensuring:
- Completely consistent dependency content for every build
- Detection of any tampering
- Build fails if checksum mismatch detected
Checksum Database (sum.golang.org):
- Global append-only list of go.sum entries
- Maintained by Google
- Ensures everyone uses same dependency contents
- Makes targeted attacks (backdoors) impossible
Key Design Decisions:
- Deterministic Builds: Version of every dependency fully determined by go.mod
- No Post-Install Hooks: Code cannot execute during fetch or build
- Immutable Versions: Published versions cannot change
2. Verify Dependencies
Check Module Integrity:
go mod verify
go get -u ./...
go mod tidy
go mod vendor
3. Scan for Vulnerabilities
Using govulncheck:
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
govulncheck -json ./...
Using OSV Scanner:
go install github.com/google/osv-scanner/cmd/osv-scanner@latest
osv-scanner --lockfile=go.mod
4. Real-World Supply Chain Attacks
Typosquatting Examples:
- Malicious MongoDB Go module:
github.com/qiniiu/qmgo (vs legitimate github.com/qiniu/qmgo)
- Backdoored BoltDB typosquat exploited Go Module Proxy caching
Prevention:
- Carefully verify package names
- Check package popularity and maintenance
- Review code of new dependencies
- Use
GOPRIVATE for internal modules
- Monitor dependency updates
- Maintain minimal dependency tree
5. Security Best Practices
module myapp
go 1.21
require (
github.com/trusted/package v1.2.3
)
exclude github.com/bad/package v1.0.0
CI/CD Integration:
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: "1.21"
- name: Run govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
- name: Verify modules
run: go mod verify
Resources:
Security Checklist
General Security
Input Validation
Cryptography
gRPC Security
Concurrency
Dependencies
Error Handling
Configuration
Testing
Additional Resources
Official Go Security
OWASP Resources
Security Tools
Community Resources
Conclusion
Security is an ongoing process, not a one-time task. This guide covers the major vulnerability classes in Go applications, but new vulnerabilities are discovered regularly. Stay informed about:
- Security advisories from the Go team
- CVE databases for Go and your dependencies
- Community security discussions and best practices
- Regular security audits of your codebase
- Emerging attack patterns in the Go ecosystem
Remember: Defense in depth is key. Don't rely on a single security measure; implement multiple layers of protection. When in doubt, consult security experts and follow the principle of least privilege.
For the latest security updates, always refer to the official Go security resources and maintain a security-first mindset in your development process.
Document Version: 1.0
Last Updated: December 2024
Author: Compiled from official Go documentation, OWASP resources, and community security research
License: This guide is provided for educational purposes