Token导航 LogoToken导航TokenDH.com
前端设计可写文件github未标认证来源可访问许可证需确认审计通过

go-security去保安

Agent Skill

用于辅助安全审计、权限检查、凭据风险、认证流程和常见漏洞排查。它适合让 Agent 梳理敏感配置、检查依赖风险、分析鉴权逻辑或生成安全复核清单。使用时不能把工具输出直接当最终结论,涉及密钥、令牌、用户数据或生产系统时,应先确认最小权限、脱敏方式和操作边界。

总安装

618

周安装

26

GitHub Stars

12

下载量

216
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:go-security(去保安)
来源仓库:https://github.com/claude-dev-suite/claude-dev-suite
仓库路径:skills/go-security
安装命令:
npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill go-security
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill go-security

简介

用于辅助安全审计、权限检查和漏洞排查,支持凭据风险分析。

  • 适合梳理敏感配置、检查依赖风险和生成安全复核清单。
  • 不能直接把工具输出当最终结论,需人工复核。go-security 属于前端设计类 Skill,可作为该场景下的辅助能力补充。
  • 涉及密钥或生产系统时应确认最小权限和操作边界。
  • 安装前建议确认来源仓库维护状态和权限范围。

SKILL.md

Go Security - Quick Reference

When NOT to Use This Skill

  • General OWASP concepts - Use owasp or owasp-top-10 skill
  • Java security - Use java-security skill
  • Python security - Use python-security skill
  • Secrets management - Use secrets-management skill
Deep Knowledge: Use mcp__documentation__fetch_docs with technology: go for Go security documentation.

Dependency Auditing

# Go built-in vulnerability check (Go 1.18+)
go list -m -json all | go run golang.org/x/vuln/cmd/govulncheck@latest

# govulncheck direct
govulncheck ./...

# Check for outdated modules
go list -u -m all

# Verify module checksums
go mod verify

# Snyk for Go
snyk test

CI/CD Integration

# GitHub Actions
- name: Security audit
  run: |
    go install golang.org/x/vuln/cmd/govulncheck@latest
    govulncheck ./...

- name: Snyk scan
  uses: snyk/actions/golang@master
  with:
    args: --severity-threshold=high

SQL Injection Prevention

database/sql - Safe

// SAFE - Parameterized query with ?
row := db.QueryRow("SELECT * FROM users WHERE email = ?", email)

// SAFE - Parameterized query with $n (PostgreSQL)
row := db.QueryRow("SELECT * FROM users WHERE email = $1", email)

// SAFE - Named parameters with sqlx
row := db.NamedQuery("SELECT * FROM users WHERE email = :email",
    map[string]interface{}{"email": email})

database/sql - UNSAFE

// UNSAFE - String formatting
query := fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email)  // NEVER!
row := db.QueryRow(query)

// UNSAFE - String concatenation
query := "SELECT * FROM users WHERE email = '" + email + "'"  // NEVER!

GORM - Safe

// SAFE - GORM where clause
var user User
db.Where("email = ?", email).First(&user)

// SAFE - GORM struct condition
db.Where(&User{Email: email}).First(&user)

// SAFE - GORM map condition
db.Where(map[string]interface{}{"email": email}).First(&user)

GORM - UNSAFE

// UNSAFE - Raw with formatting
db.Raw(fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email))  // NEVER!

XSS Prevention

html/template (Auto-escaping)

// SAFE - html/template auto-escapes
import "html/template"

tmpl := template.Must(template.ParseFiles("page.html"))
tmpl.Execute(w, data)  // data.UserInput is auto-escaped
<!-- Template - auto-escaped -->
<p>{{.UserInput}}</p>

text/template - UNSAFE for HTML

// UNSAFE for HTML - text/template does NOT escape
import "text/template"  // Only for non-HTML content!

Manual Sanitization

import "html"

// Escape HTML entities
safeString := html.EscapeString(userInput)

// For rich HTML, use bluemonday
import "github.com/microcosm-cc/bluemonday"

p := bluemonday.UGCPolicy()
safeHTML := p.Sanitize(userInput)

Authentication - JWT

JWT with golang-jwt

import (
    "github.com/golang-jwt/jwt/v5"
    "time"
)

var jwtKey = []byte(os.Getenv("JWT_SECRET"))

type Claims struct {
    UserID string `json:"user_id"`
    Email  string `json:"email"`
    jwt.RegisteredClaims
}

func GenerateToken(userID, email string) (string, error) {
    claims := &Claims{
        UserID: userID,
        Email:  email,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
            IssuedAt:  jwt.NewNumericDate(time.Now()),
            Issuer:    "myapp",
        },
    }

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(jwtKey)
}

func ValidateToken(tokenString string) (*Claims, error) {
    claims := &Claims{}

    token, err := jwt.ParseWithClaims(tokenString, claims,
        func(token *jwt.Token) (interface{}, error) {
            // Validate signing method
            if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                return nil, fmt.Errorf("unexpected signing method")
            }
            return jwtKey, nil
        })

    if err != nil || !token.Valid {
        return nil, err
    }

    return claims, nil
}

Password Hashing with bcrypt

import "golang.org/x/crypto/bcrypt"

func HashPassword(password string) (string, error) {
    // Cost 12 is recommended
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), 12)
    return string(bytes), err
}

func CheckPassword(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

Password Hashing with Argon2

import "golang.org/x/crypto/argon2"

func HashPasswordArgon2(password string) (string, error) {
    salt := make([]byte, 16)
    if _, err := rand.Read(salt); err != nil {
        return "", err
    }

    hash := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32)

    // Encode for storage
    return base64.StdEncoding.EncodeToString(append(salt, hash...)), nil
}

Input Validation

Using go-playground/validator

import "github.com/go-playground/validator/v10"

type CreateUserRequest struct {
    Email    string `json:"email" validate:"required,email,max=255"`
    Password string `json:"password" validate:"required,min=12,max=128,containsany=ABCDEFGHIJKLMNOPQRSTUVWXYZ,containsany=abcdefghijklmnopqrstuvwxyz,containsany=0123456789,containsany=@$!%*?&"`
    Name     string `json:"name" validate:"required,min=2,max=100,alpha"`
}

var validate = validator.New()

func CreateUser(c *gin.Context) {
    var req CreateUserRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    if err := validate.Struct(req); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    // req is validated
}

Custom Validation

// Register custom validation
validate.RegisterValidation("safe_string", func(fl validator.FieldLevel) bool {
    return regexp.MustCompile(`^[a-zA-Z\s\-']+$`).MatchString(fl.Field().String())
})

type Request struct {
    Name string `validate:"required,safe_string"`
}

Command Injection Prevention

import "os/exec"

// SAFE - Use exec.Command with separate arguments
cmd := exec.Command("ls", "-la", directory)
output, err := cmd.Output()

// SAFE - Use exec.CommandContext for timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "ls", "-la", directory)

// UNSAFE - Shell expansion
cmd := exec.Command("sh", "-c", "ls -la " + directory)  // NEVER with user input!

// UNSAFE - Using os.system equivalent
// Go doesn't have os.system, but avoid shell=true patterns

Secure File Upload

func UploadHandler(w http.ResponseWriter, r *http.Request) {
    // Limit request size
    r.Body = http.MaxBytesReader(w, r.Body, 10<<20) // 10 MB

    file, header, err := r.FormFile("file")
    if err != nil {
        http.Error(w, "File too large or invalid", http.StatusBadRequest)
        return
    }
    defer file.Close()

    // Validate content type
    allowedTypes := map[string]bool{
        "image/jpeg":      true,
        "image/png":       true,
        "application/pdf": true,
    }

    buffer := make([]byte, 512)
    file.Read(buffer)
    contentType := http.DetectContentType(buffer)
    file.Seek(0, 0) // Reset reader

    if !allowedTypes[contentType] {
        http.Error(w, "File type not allowed", http.StatusBadRequest)
        return
    }

    // Generate safe filename
    ext := filepath.Ext(header.Filename)
    safeName := fmt.Sprintf("%s%s", uuid.New().String(), ext)

    // Save outside web root
    destPath := filepath.Join(uploadDir, safeName)
    dest, err := os.Create(destPath)
    if err != nil {
        http.Error(w, "Failed to save file", http.StatusInternalServerError)
        return
    }
    defer dest.Close()

    io.Copy(dest, file)

    json.NewEncoder(w).Encode(map[string]string{"filename": safeName})
}

CORS Configuration

Gin

import "github.com/gin-contrib/cors"

r := gin.Default()

r.Use(cors.New(cors.Config{
    AllowOrigins:     []string{"https://myapp.com"},
    AllowMethods:     []string{"GET", "POST", "PUT", "DELETE"},
    AllowHeaders:     []string{"Authorization", "Content-Type"},
    AllowCredentials: true,
    MaxAge:           12 * time.Hour,
}))

Standard Library

func corsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        origin := r.Header.Get("Origin")
        allowedOrigins := map[string]bool{"https://myapp.com": true}

        if allowedOrigins[origin] {
            w.Header().Set("Access-Control-Allow-Origin", origin)
            w.Header().Set("Access-Control-Allow-Credentials", "true")
        }

        if r.Method == "OPTIONS" {
            w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
            w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type")
            w.WriteHeader(http.StatusNoContent)
            return
        }

        next.ServeHTTP(w, r)
    })
}

Security Headers Middleware

func securityHeaders(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("X-Content-Type-Options", "nosniff")
        w.Header().Set("X-Frame-Options", "DENY")
        w.Header().Set("X-XSS-Protection", "0") // Use CSP instead
        w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
        w.Header().Set("Content-Security-Policy", "default-src 'self'")
        w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")

        next.ServeHTTP(w, r)
    })
}

Rate Limiting

import "golang.org/x/time/rate"

// Per-IP rate limiter
type IPRateLimiter struct {
    ips map[string]*rate.Limiter
    mu  *sync.RWMutex
    r   rate.Limit
    b   int
}

func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
    return &IPRateLimiter{
        ips: make(map[string]*rate.Limiter),
        mu:  &sync.RWMutex{},
        r:   r,
        b:   b,
    }
}

func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
    i.mu.Lock()
    defer i.mu.Unlock()

    limiter, exists := i.ips[ip]
    if !exists {
        limiter = rate.NewLimiter(i.r, i.b)
        i.ips[ip] = limiter
    }

    return limiter
}

// Middleware
func rateLimitMiddleware(limiter *IPRateLimiter) gin.HandlerFunc {
    return func(c *gin.Context) {
        ip := c.ClientIP()
        if !limiter.GetLimiter(ip).Allow() {
            c.AbortWithStatusJSON(429, gin.H{"error": "Too many requests"})
            return
        }
        c.Next()
    }
}

Secrets Management

import "os"

// Load from environment
type Config struct {
    JWTSecret    string
    DatabaseURL  string
    APIKey       string
}

func LoadConfig() (*Config, error) {
    jwtSecret := os.Getenv("JWT_SECRET")
    if jwtSecret == "" {
        return nil, errors.New("JWT_SECRET not set")
    }

    return &Config{
        JWTSecret:   jwtSecret,
        DatabaseURL: os.Getenv("DATABASE_URL"),
        APIKey:      os.Getenv("API_KEY"),
    }, nil
}

// NEVER hardcode secrets
// const jwtSecret = "hardcoded-secret"  // NEVER!

Logging Security Events

import "log/slog"

func LogLoginAttempt(username string, success bool, ip string) {
    slog.Info("login attempt",
        "user", username,
        "success", success,
        "ip", ip,
    )
}

func LogAccessDenied(userID string, resource string, ip string) {
    slog.Warn("access denied",
        "user_id", userID,
        "resource", resource,
        "ip", ip,
    )
}

// NEVER log sensitive data
// slog.Info("password", "value", password)  // NEVER!

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
fmt.Sprintf in SQLSQL injectionUse parameterized queries
text/template for HTMLXSS vulnerabilityUse html/template
Hardcoded secretsSecret exposureUse environment variables
exec.Command("sh", "-c", input)Command injectionUse separate arguments
Weak JWT signingToken forgeryUse HS256 minimum, verify alg
No request size limitDoS attackUse MaxBytesReader
Using MD5/SHA1 for passwordsEasily crackedUse bcrypt or argon2

Quick Troubleshooting

IssueLikely CauseSolution
govulncheck finds CVEVulnerable dependencyUpdate with go get -u
JWT validation failsWrong signing methodVerify algorithm in ParseWithClaims
CORS errorOrigin not allowedAdd origin to allowed list
bcrypt too slowCost factor too highUse cost 10-12
File upload failsSize limit exceededIncrease MaxBytesReader limit
Template not escapingUsing text/templateSwitch to html/template

Security Scanning Commands

# Vulnerability check
govulncheck ./...

# Static analysis
staticcheck ./...
go vet ./...

# Security linter
gosec ./...

# Dependency check
go list -m -json all | nancy sleuth

# Snyk
snyk test

# Check for secrets
gitleaks detect
trufflehog git file://.

Related Skills

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

37.7%
按下载量换算81

Claude

29.74%
按下载量换算64

Cursor

19.97%
按下载量换算43

Gemini CLI

10.14%
按下载量换算22

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

可写文件

该 Skill 可能写入或修改本地文件,使用前需要确认目标目录和修改范围。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills