Detect problematic JSON tags with dash prefix
Description
This rule detects a security vulnerability in Go's JSON unmarshaling. When a struct field has a JSON tag that starts with -,
, it can be unexpectedly unmarshaled with the -
key.
According to the Go documentation, if the field tag is -
, the field should be omitted. However, a field with name -
can still be unmarshaled using the tag -,
.
This creates a security issue where developers think they are preventing a field from being unmarshaled (like IsAdmin
in authentication), but attackers can still set that field by providing the -
key in JSON input.
go
type User struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
IsAdmin bool `json:"-,omitempty"` // Intended to prevent marshaling
}
// This still works and sets IsAdmin to true!
json.Unmarshal([]byte(`{"-": true}`), &user)
// Result: main.User{Username:"", Password:"", IsAdmin:true}
YAML
yaml
id: unmarshal-tag-is-dash
severity: error
message: Struct field can be decoded with the `-` key because the JSON tag
starts with a `-` but is followed by a comma.
rule:
pattern: '`$TAG`'
inside:
kind: field_declaration
constraints:
TAG:
regex: json:"-,.*"
Example
go
package main
type TestStruct1 struct {
A string `json:"id"` // ok
}
type TestStruct2 struct {
B string `json:"-,omitempty"` // wrong
}
type TestStruct3 struct {
C string `json:"-,123"` // wrong
}
type TestStruct4 struct {
D string `json:"-,"` // wrong
}
Fix
To properly omit a field from JSON marshaling/unmarshaling, use just -
without a comma:
go
type User struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
IsAdmin bool `json:"-"` // Correctly prevents marshaling/unmarshaling
}
Contributed by
Inspired by Trail of Bits blog post and their public Semgrep rule.