Misuse of null/empty variables
| Vulnerability potential | Low |
| DDoS potential | Low |
Null/empty variables might be used incorrectly
Impact
In Go a nil slice or map and an empty-but-allocated one are almost but not
quite interchangeable, and conflating the two leads to subtle bugs. Ranging over,
reading from, or taking len() of a nil slice or map works fine, which lulls
developers into treating nil and empty as the same — until a nil map is
written to, which panics, or until serialization, equality, or “was this field
provided?” logic needs to tell them apart. The result is intermittent panics on
write, JSON that emits null where [] was expected (breaking clients), and
business logic that cannot distinguish “no value supplied” from “explicitly
empty”.
Vulnerability potential
Direct security impact is limited. The main concern is availability:
- Writing to a
nilmap (m[k] = vwhenm == nil) panics withassignment to entry in nil map; if such a path is reachable from request handling it becomes a crash-on-demand denial-of-service primitive. - Logic that conflates nil with empty can misclassify input — for example treating a missing list as an empty allow/deny set — which, depending on the surrounding code, may relax a check; the flaw there is the ambiguous semantics, not memory safety.
Technical details
A nil slice has no backing array but len and cap of 0 and is fully usable
for reads, append (which allocates), and range. A nil map supports reads
(returning the zero value) and len, but panics on assignment because there
is no hash table to insert into. This asymmetry is the crux of the defect.
nil vs empty are observably different
- JSON: a
nilslice marshals tonull; an empty non-nil slice ([]T{}) marshals to[]. Clients and schemas often care. - Equality / presence: only
nilanswers “field never set”;[]T{}answers “set, but empty”. Collapsing them loses that distinction. reflect.DeepEqual(nilSlice, emptySlice)isfalse.
Strings and pointers
Go strings cannot be nil; the empty string "" is the zero value, so “nil vs
empty” for strings is really “empty vs non-empty” — but pointer-to-string or
interface fields reintroduce the nil/empty/absent three-way distinction.
Catching the issue
Static analysis
staticcheck flags writes to potentially-nil maps and some nil-related mistakes;
golangci-lint with nilness helps. There is no single check that proves
intent, so the discipline matters more than the tool.
Conventions
Always initialize a map with make(map[K]V) (or a literal) before writing.
Decide per type whether your API treats nil and empty alike, and document it; for
JSON responses pick []T{} when clients expect an array. When presence matters
(PATCH semantics, optional fields), use pointers or a dedicated “set” flag rather
than overloading empty.
How to reproduce
Run the program; reads from the nil map are fine, but the write panics with “assignment to entry in nil map”.
package main
import "fmt"
func main() {
var counts map[string]int // nil map (not made)
fmt.Println(len(counts)) // 0 — fine
fmt.Println(counts["x"]) // 0 — read of missing key is fine
for range counts { // ranging a nil map is fine
}
counts["x"]++ // panic: assignment to entry in nil map
}