Provides security checklists and best practices for developing secure Go applications.
Install
mkdir -p .claude/skills/security-review-zzh0u && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/12272" && unzip -o skill.zip -d .claude/skills/security-review-zzh0u && rm skill.zipInstalls to .claude/skills/security-review-zzh0u
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment/sensitive features. Provides comprehensive security checklist and patterns.Key capabilities
- →Ensure secrets are loaded from environment variables or secret managers
- →Validate all user inputs using struct tags or libraries
- →Restrict file uploads by size, content type, and extension
- →Implement secure authentication and authorization patterns
- →Prevent common Go-specific security vulnerabilities
How it works
The skill provides a checklist and code patterns for Go applications, covering secrets management, input validation, authentication, and other security aspects. It guides the user to implement secure coding practices and avoid common pitfalls.
Inputs & outputs
When to use security-review
- →Review Go auth implementation
- →Secure configuration handling
- →Validate HTTP API inputs
About this skill
Security Review Skill (Go Edition)
This skill ensures Go code follows security best practices and identifies potential vulnerabilities specific to Go applications.
When to Activate
- Implementing authentication or authorization in Go web applications
- Handling user input or file uploads in Gin/Go HTTP handlers
- Creating new API endpoints in Go
- Working with secrets or credentials in Go configuration
- Implementing payment or sensitive features in Go
- Storing or transmitting sensitive data
- Integrating third-party APIs with Go clients
Security Checklist
1. Secrets Management
❌ NEVER Do This
// Hardcoded secrets in source code
const apiKey = "sk-proj-xxxxx"
const dbPassword = "password123"
// In configuration structs
type Config struct {
JWTSecret string `json:"jwt_secret"` // Will be hardcoded in JSON
}
✅ ALWAYS Do This
// Use environment variables or dedicated secret management
import (
"os"
"fmt"
)
// Load from environment
jwtSecret := os.Getenv("JWT_SECRET")
if jwtSecret == "" {
return fmt.Errorf("JWT_SECRET environment variable not set")
}
// Or use configuration struct with validation
type Config struct {
JWTSecret string `env:"JWT_SECRET,required"`
DatabaseURL string `env:"DATABASE_URL,required"`
APIKey string `env:"API_KEY"`
}
// Use packages like github.com/caarlos0/env for structured env loading
import "github.com/caarlos0/env/v6"
var cfg Config
if err := env.Parse(&cfg); err != nil {
log.Fatal("Failed to parse config:", err)
}
Verification Steps
- No hardcoded API keys, tokens, or passwords in source code
- All secrets loaded from environment variables or secret managers
- Configuration files with secrets excluded from git (
.env,config/local.yaml) - No secrets in git history (check with
git log -p -S "password") - Production secrets managed by platform (Kubernetes Secrets, AWS Secrets Manager, etc.)
- Secrets validated at application startup
2. Input Validation
Always Validate User Input
// Use struct tags for validation (Gin framework example)
type CreateUserRequest struct {
Email string `json:"email" binding:"required,email"`
Name string `json:"name" binding:"required,min=1,max=100"`
Age int `json:"age" binding:"required,min=0,max=150"`
Password string `json:"password" binding:"required,min=8"`
}
// In Gin handler
func CreateUser(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": "Invalid input", "details": err.Error()})
return
}
// Proceed with validated request
user, err := service.CreateUser(req)
if err != nil {
c.JSON(500, gin.H{"error": "Internal server error"})
return
}
c.JSON(200, gin.H{"data": user})
}
// Custom validation with go-playground/validator
import "github.com/go-playground/validator/v10"
var validate = validator.New()
func validateUser(req CreateUserRequest) error {
if err := validate.Struct(req); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
// Custom business logic validation
if strings.Contains(strings.ToLower(req.Name), "admin") {
return fmt.Errorf("name cannot contain 'admin'")
}
return nil
}
File Upload Validation
import (
"mime/multipart"
"path/filepath"
"strings"
)
func validateFileUpload(fileHeader *multipart.FileHeader) error {
// Size check (5MB max)
const maxSize = 5 * 1024 * 1024 // 5MB
if fileHeader.Size > maxSize {
return fmt.Errorf("file too large (max 5MB)")
}
// Content type check
contentType := fileHeader.Header.Get("Content-Type")
allowedTypes := []string{"image/jpeg", "image/png", "image/gif"}
validType := false
for _, t := range allowedTypes {
if contentType == t {
validType = true
break
}
}
if !validType {
return fmt.Errorf("invalid file type: %s", contentType)
}
// Extension check (additional safety)
ext := strings.ToLower(filepath.Ext(fileHeader.Filename))
allowedExts := []string{".jpg", ".jpeg", ".png", ".gif"}
validExt := false
for _, e := range allowedExts {
if ext == e {
validExt = true
break
}
}
if !validExt {
return fmt.Errorf("invalid file extension: %s", ext)
}
// Check filename for path traversal
if strings.Contains(fileHeader.Filename, "..") || strings.Contains(fileHeader.Filename, "/") {
return fmt.Errorf("invalid filename")
}
return nil
}
// In Gin handler for file upload
func UploadFile(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(400, gin.H{"error": "No file uploaded"})
return
}
if err := validateFileUpload(file); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// Save the file securely
safeFilename := generateSafeFilename(file.Filename)
dst := filepath.Join("uploads", safeFilename)
if err := c.SaveUploadedFile(file, dst); err != nil {
c.JSON(500, gin.H{"error": "Failed to save file"})
return
}
c.JSON(200, gin.H{"message": "File uploaded successfully"})
}
Verification Steps
- All user inputs validated with struct tags or validation libraries
- File uploads restricted by size, content type, and extension
- No direct concatenation of user input in queries or commands
- Whitelist validation (allow known good values) instead of blacklist
- Error messages generic, no sensitive information exposed
- Path traversal prevention for file uploads
- Input length limits enforced to prevent DoS attacks
3. SQL Injection Prevention
❌ NEVER Concatenate SQL
// DANGEROUS - SQL Injection vulnerability
func getUserByEmailUnsafe(email string) (*User, error) {
query := fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email)
var user User
err := db.Raw(query).Scan(&user).Error
return &user, err
}
// Also dangerous: using Sprintf with query conditions
func searchUsersUnsafe(search string) ([]User, error) {
condition := ""
if search != "" {
condition = fmt.Sprintf("WHERE name LIKE '%%%s%%'", search)
}
query := fmt.Sprintf("SELECT * FROM users %s", condition)
var users []User
err := db.Raw(query).Scan(&users).Error
return users, err
}
✅ ALWAYS Use Parameterized Queries
// Safe - GORM parameterized queries
func getUserByEmailSafe(email string) (*User, error) {
var user User
err := db.Where("email = ?", email).First(&user).Error
return &user, err
}
// Safe - GORM with map conditions
func searchUsersSafe(search string) ([]User, error) {
dbQuery := db.Model(&User{})
if search != "" {
dbQuery = dbQuery.Where("name LIKE ?", "%"+search+"%")
}
var users []User
err := dbQuery.Find(&users).Error
return users, err
}
// Safe - Raw SQL with parameterized queries
func getUserRawSafe(email string) (*User, error) {
var user User
err := db.Raw("SELECT * FROM users WHERE email = ?", email).Scan(&user).Error
return &user, err
}
// Safe - PostgreSQL style numbered parameters
func getUsersByIDs(ids []uint) ([]User, error) {
var users []User
query := "SELECT * FROM users WHERE id IN (?)"
err := db.Raw(query, ids).Scan(&users).Error
return users, err
}
// Safe - Using GORM's Exec with parameters
func updateUserEmail(userID uint, newEmail string) error {
result := db.Exec("UPDATE users SET email = ? WHERE id = ?", newEmail, userID)
return result.Error
}
Verification Steps
- All database queries use parameterized queries (?, $1, @param placeholders)
- No string concatenation or fmt.Sprintf for SQL query construction
- ORM (GORM) used correctly with Where(), Find(), Raw() with parameters
- User input never directly interpolated into SQL strings
- Raw SQL queries always use parameter binding
- SQL query builders used for complex dynamic queries
- Database driver's parameterized query support utilized
4. Authentication & Authorization
JWT Token Handling and Storage
// ❌ WRONG: Storing tokens in localStorage (vulnerable to XSS in SPA)
// Frontend JavaScript: localStorage.setItem('token', token)
// Go backend returning token in JSON response (insecure for web)
func LoginHandler(c *gin.Context) {
// ... authenticate user ...
token, err := generateJWT(user)
if err != nil {
c.JSON(500, gin.H{"error": "Failed to generate token"})
return
}
// Insecure: token in JSON response (client stores in localStorage)
c.JSON(200, gin.H{"token": token}) // ❌ VULNERABLE TO XSS
}
// ✅ CORRECT: httpOnly, Secure, SameSite cookies
func LoginHandlerSecure(c *gin.Context) {
// ... authenticate user ...
token, err := generateJWT(user)
if err != nil {
c.JSON(500, gin.H{"error": "Failed to generate token"})
return
}
// Set secure httpOnly cookie
c.SetCookie(
"token", // name
token, // value
3600, // max age in seconds
"/", // path
".example.com", // domain (set appropriately)
true, // secure (HTTPS only)
true, // httpOnly (inaccessible to JavaScript)
)
c.JSON(200, gin.H{"message": "Login successful"})
}
// JWT generation and validation using golang-jwt/jwt
import "github.com/golang-jwt/jwt/v4"
type Claims struct {
UserID uint `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func generateJWT(user User) (string, error) {
claims := &Claims{
UserID: user.ID,
Role: user.Role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresA
---
*Content truncated.*
When not to use it
- →When hardcoding API keys, tokens, or passwords in source code
- →When configuration structs directly expose secrets in JSON
- →When user inputs are not validated before processing
Limitations
- →The skill focuses on Go-specific security practices.
- →It requires manual verification steps for each security aspect.
- →It does not automatically fix vulnerabilities, but provides guidance.
How it compares
This skill offers Go-specific security guidance and patterns, directly addressing common vulnerabilities in Go applications, unlike general security checklists that may not cover language-specific nuances.
Compared to similar skills
security-review side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| security-review (this skill) | 0 | 6mo | Review | Intermediate |
| security-header-generator | 5 | 9mo | Caution | Intermediate |
| backend-security-coder | 24 | 4mo | No flags | Intermediate |
| api-security-best-practices | 15 | 6mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
security-header-generator
Dexploarer
Generates security HTTP headers (CSP, HSTS, CORS, etc.) for web applications to prevent common attacks. Use when user asks to "add security headers", "setup CSP", "configure CORS", "secure headers", or "HSTS setup".
backend-security-coder
sickn33
Expert in secure backend coding practices specializing in input validation, authentication, and API security. Use PROACTIVELY for backend security implementations or security code reviews.
api-security-best-practices
davila7
Implement secure API design patterns including authentication, authorization, input validation, rate limiting, and protection against common API vulnerabilities
springboot-security
affaan-m
Spring Security best practices for authn/authz, validation, CSRF, secrets, headers, rate limiting, and dependency security in Java Spring Boot services.
windows-kernel-security
gmh5225
Guide for Windows kernel security research including driver development, system callbacks, security features, and kernel exploitation. Use this skill when working with Windows drivers, PatchGuard, DSE, or kernel-level security mechanisms.
django-security
affaan-m
Django security best practices, authentication, authorization, CSRF protection, SQL injection prevention, XSS prevention, and secure deployment configurations.