Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Golang Safety

ASecurity

Defensive Golang coding to prevent panics, silent data corruption, and subtle runtime bugs. Use when encountering nil panics, append aliasing, map concurrent access, float comparison pitfalls, or zero-value design questions. Also use when reviewing code for nil-safety, numeric conversion overflow, resource lifecycle issues (defer in loops), or defensive copying of slices and maps.

8 stars
0 votes
0 copies
0 views
Added 10/5/2026
code-qualitygobashsqlexpressdebugginggitsecurityperformance

Works with

claude code

Security Analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned 10/5/2026

$npx -y skills add tstapler/dotfiles --skill golang-safety --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Golang Safety?

Add the live security badge to your README β€” it updates automatically with every re-scan.

Security grade badge for Golang Safety
[![Security: A β€” Skills Directory](https://www.skillsdirectory.com/api/skills/tstapler-golang-safety/badge)](https://www.skillsdirectory.com/skills/tstapler-golang-safety)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: golang-safety
description: "Defensive Golang coding to prevent panics, silent data corruption, and subtle runtime bugs. Use when encountering nil panics, append aliasing, map concurrent access, float comparison pitfalls, or zero-value design questions. Also use when reviewing code for nil-safety, numeric conversion overflow, resource lifecycle issues (defer in loops), or defensive copying of slices and maps."
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents, and for projects using Golang.
metadata:
  author: samber
  version: "1.2.1"
  openclaw:
    emoji: "πŸ›‘"
    homepage: https://github.com/samber/cc-skills-golang
    requires:
      bins:
        - go
    install: []
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent
---

**Persona:** You are a defensive Go engineer. You treat every untested assumption about nil, capacity, and numeric range as a latent crash waiting to happen.

# Go Safety: Correctness & Defensive Coding

Prevents programmer mistakes β€” bugs, panics, and silent data corruption in normal (non-adversarial) code. Security handles attackers; safety handles ourselves.

## Best Practices Summary

1. **Prefer generics over `any`** when the type set is known β€” compiler catches mismatches instead of runtime panics
2. **Always use safe type assertions** β€” for normal interfaces use comma-ok (`v, ok := x.(T)`); for reflection in Go 1.25+ prefer `reflect.TypeAssert[T](value)` over `value.Interface().(T)`.
3. **Typed nil pointer in an interface is not `== nil`** β€” the type descriptor makes it non-nil
4. **Writing to a nil map panics** β€” always initialize before use
5. **`append` may reuse the backing array** β€” both slices share memory if capacity allows, silently corrupting each other
6. **Return defensive copies** from exported functions β€” otherwise callers mutate your internals
7. **`defer` runs at function exit, not loop iteration** β€” extract loop body to a function
8. **Integer conversions truncate silently** β€” `int64` to `int32` wraps without error
9. **Float arithmetic is not exact** β€” use epsilon comparison or `math/big`
10. **Design useful zero values** β€” nil map fields panic on first write; use lazy init
11. **Use `sync.Once` for lazy init** β€” guarantees exactly-once even under concurrency

## Nil Safety

Nil-related panics are the most common crash in Go.

### The nil interface trap

Interfaces store (type, value). An interface is `nil` only when both are nil. Returning a typed nil pointer sets the type descriptor, making it non-nil:

```go
// βœ— Dangerous β€” interface{type: *MyHandler, value: nil} is not == nil
func getHandler() http.Handler {
    var h *MyHandler // nil pointer
    if !enabled {
        return h // interface{type: *MyHandler, value: nil} != nil
    }
    return h
}

// βœ“ Good β€” return nil explicitly
func getHandler() http.Handler {
    if !enabled {
        return nil // interface{type: nil, value: nil} == nil
    }
    return &MyHandler{}
}
```

### Nil map, slice, and channel behavior

| Type    | Index into nil | Write to nil   | Len/Cap of nil | Range over nil |
| ------- | -------------- | -------------- | -------------- | -------------- |
| Map     | Zero value     | **panic**      | 0              | 0 iterations   |
| Slice   | **panic**      | **panic**      | 0              | 0 iterations   |
| Channel | Blocks forever | Blocks forever | 0              | Blocks forever |

```go
// βœ— Bad β€” nil map panics on write
var m map[string]int
m["key"] = 1

// βœ“ Good β€” initialize or lazy-init in methods
m := make(map[string]int)

func (r *Registry) Add(name string, val int) {
    if r.items == nil { r.items = make(map[string]int) }
    r.items[name] = val
}
```

See **[Nil Safety Deep Dive](./references/nil-safety.md)** for nil receivers, nil in generics, and nil interface performance.

## Slice & Map Safety

### Slice aliasing β€” the append trap

`append` reuses the backing array if capacity allows. Both slices then share memory:

```go
// βœ— Dangerous β€” a and b share backing array
a := make([]int, 3, 5)
b := append(a, 4)
b[0] = 99 // also modifies a[0]

// βœ“ Good β€” full slice expression forces new allocation
b := append(a[:len(a):len(a)], 4)
```

### Map concurrent access

Maps MUST NOT be accessed concurrently β€” β†’ see `samber/cc-skills-golang@golang-concurrency` for sync primitives.

See **[Slice and Map Deep Dive](./references/slice-map-safety.md)** for range pitfalls, subslice memory retention, and `slices.Clone`/`maps.Clone`.

## Numeric Safety

### Implicit type conversions truncate silently

```go
// βœ— Bad β€” silently wraps around if val > math.MaxInt32 (3B becomes -1.29B)
var val int64 = 3_000_000_000
i32 := int32(val) // -1294967296 (silent wraparound)

// βœ“ Good β€” check before converting
if val > math.MaxInt32 || val < math.MinInt32 {
    return fmt.Errorf("value %d overflows int32", val)
}
i32 := int32(val)
```

### Float comparison

```go
// βœ— Bad β€” floating point arithmetic is not exact
var a, b, c float64 = 0.1, 0.2, 0.3
a+b == c // false

// βœ“ Good β€” use epsilon comparison
const epsilon = 1e-9
math.Abs((a+b)-c) < epsilon // true
```

### Division by zero

Integer division by zero panics. Float division by zero produces `+Inf`, `-Inf`, or `NaN`.

```go
func avg(total, count int) (int, error) {
    if count == 0 {
        return 0, errors.New("division by zero")
    }
    return total / count, nil
}
```

For integer overflow as a security vulnerability, see the `samber/cc-skills-golang@golang-security` skill section.

## Resource Safety

### defer in loops β€” resource accumulation

`defer` runs at _function_ exit, not loop iteration. Resources accumulate until the function returns:

```go
// βœ— Bad β€” all files stay open until function returns
for _, path := range paths {
    f, _ := os.Open(path)
    defer f.Close() // deferred until function exits
    process(f)
}

// βœ“ Good β€” extract to function so defer runs per iteration
for _, path := range paths {
    if err := processOne(path); err != nil { return err }
}
func processOne(path string) error {
    f, err := os.Open(path)
    if err != nil { return err }
    defer f.Close()
    return process(f)
}
```

### Goroutine leaks

β†’ See `samber/cc-skills-golang@golang-concurrency` for goroutine lifecycle and leak prevention.

## Immutability & Defensive Copying

Exported functions returning slices/maps SHOULD return defensive copies.

### Protecting struct internals

```go
// βœ— Bad β€” exported slice field, anyone can mutate
type Config struct {
    Hosts []string
}

// βœ“ Good β€” unexported field with accessor returning a copy
type Config struct {
    hosts []string
}

func (c *Config) Hosts() []string {
    return slices.Clone(c.hosts)
}
```

## Initialization Safety

### Zero-value design

Design types so `var x MyType` is safe β€” prevents "forgot to initialize" bugs:

```go
var mu sync.Mutex   // βœ“ usable at zero value
var buf bytes.Buffer // βœ“ usable at zero value

// βœ— Bad β€” nil map panics on write
type Cache struct { data map[string]any }
```

### sync.Once for lazy initialization

```go
type DB struct {
    once sync.Once
    conn *sql.DB
}

func (db *DB) connection() *sql.DB {
    db.once.Do(func() {
        db.conn, _ = sql.Open("postgres", connStr)
    })
    return db.conn
}
```

### init() function pitfalls

β†’ See `samber/cc-skills-golang@golang-design-patterns` for why init() should be avoided in favor of explicit constructors.

## Enforce with Linters

Many safety pitfalls are caught automatically by linters: `errcheck`, `forcetypeassert`, `nilerr`, `govet`, `staticcheck`. See the `samber/cc-skills-golang@golang-lint` skill for configuration and usage.

### Go 1.25+ reflection type assertions

For reflection code, prefer `reflect.TypeAssert[T]` over `value.Interface().(T)`.

```go
v := reflect.ValueOf(x)
if s, ok := reflect.TypeAssert[string](v); ok {
    use(s)
}
```

## Cross-References

- β†’ See `samber/cc-skills-golang@golang-concurrency` skill for concurrent access patterns and sync primitives
- β†’ See `samber/cc-skills-golang@golang-data-structures` skill for slice/map internals, capacity growth, and container/ packages
- β†’ See `samber/cc-skills-golang@golang-error-handling` skill for nil error interface trap
- β†’ See `samber/cc-skills-golang@golang-security` skill for security-relevant safety issues (memory safety, integer overflow)
- β†’ See `samber/cc-skills-golang@golang-troubleshooting` skill for debugging panics and race conditions

## Common Mistakes

| Mistake | Fix |
| --- | --- |
| Bare type assertion `v := x.(T)` | Panics on type mismatch, crashing the program. Use `v, ok := x.(T)` to handle gracefully |
| Returning typed nil in interface function | Interface holds (type, nil) which is != nil. Return untyped `nil` for the nil case |
| Writing to a nil map | Nil maps have no backing storage β€” write panics. Initialize with `make(map[K]V)` or lazy-init |
| Assuming `append` always copies | If capacity allows, both slices share the backing array. Use `s[:len(s):len(s)]` to force a copy |
| `defer` in a loop | `defer` runs at function exit, not loop iteration β€” resources accumulate. Extract body to a separate function |
| `int64` to `int32` without bounds check | Values wrap silently (3B β†’ -1.29B). Check against `math.MaxInt32`/`math.MinInt32` first |
| Comparing floats with `==` | IEEE 754 representation is not exact (`0.1+0.2 != 0.3`). Use `math.Abs(a-b) < epsilon` |
| Integer division without zero check | Integer division by zero panics. Guard with `if divisor == 0` before dividing |
| Returning internal slice/map reference | Callers can mutate your struct's internals through the shared backing array. Return a defensive copy |
| Multiple `init()` with ordering assumptions | `init()` execution order across files is unspecified. β†’ See `samber/cc-skills-golang@golang-design-patterns` β€” use explicit constructors |
| Blocking forever on nil channel | Nil channels block on both send and receive. Always initialize before use |

## Cross-References

- β†’ See `samber/cc-skills-golang@golang-continuous-integration` skill for automated AI-driven code review in CI using these guidelines

Attribution

tstaplertstapler
View sourceSee grades on GitHubMore from tstapler β†’
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman Review

Ultra-compressed code review comments. Cuts noise from PR feedback while preserving the actionable signal. Each comment is one line: location, problem, fix. Use when user says "review this PR", "code review", "review the diff", "/review", or invokes /caveman-review. Auto-triggers when reviewing pull requests.

1100021 votes

Caveman Commit

Ultra-compressed commit message generator. Cuts noise from commit messages while preserving intent and reasoning. Conventional Commits format. Subject ≀50 chars, body only when "why" isn't obvious. Use when user says "write a commit", "commit message", "generate commit", "/commit", or invokes /caveman-commit. Auto-triggers when staging changes.

1100021 votes

Springboot Verification

Verification loop for Spring Boot projects: build, static analysis, tests with coverage, security scans, and diff review before release or PR.

2456590 votes

Verification Loop

δΈ€δΈͺε…¨ι’ηš„ Claude Code 会话ιͺŒθ―η³»η»Ÿγ€‚

2456590 votes

Django Verification

Verification loop for Django projects: migrations, linting, tests with coverage, security scans, and deployment readiness checks before release or PR.

2456590 votes
View all in code-quality β†’