internal/bech32: avoid panic on Unicode input

Reported by Joe Doyle of Trail of Bits.
This commit is contained in:
Filippo Valsorda
2026-08-29 19:30:10 +02:00
parent 7a8f500567
commit 366cc58ca8
3 changed files with 56 additions and 1 deletions
+8 -1
View File
@@ -154,14 +154,21 @@ func Decode(s string) (hrp string, data []byte, err error) {
return "", nil, fmt.Errorf("invalid character human-readable part: s[%d]=%d", p, c)
}
}
s = strings.ToLower(s)
for p, c := range s[pos+1:] {
// Fold ASCII explicitly. Unicode case folding can turn a non-ASCII
// rune into a shorter valid charset member.
if c >= 'A' && c <= 'Z' {
c += 'a' - 'A'
}
d := strings.IndexRune(charset, c)
if d == -1 {
return "", nil, fmt.Errorf("invalid character data part: s[%d]=%v", p, c)
}
data = append(data, byte(d))
}
if len(data) < 6 {
return "", nil, fmt.Errorf("data part too short")
}
if !verifyChecksum(hrp, data) {
return "", nil, fmt.Errorf("invalid checksum")
}
+20
View File
@@ -93,3 +93,23 @@ func TestBech32(t *testing.T) {
}
}
}
func TestDecodeShortDataPart(t *testing.T) {
kelvin := string(rune(0x212A))
for _, s := range []string{
"AA3100AC" + kelvin,
"BK1" + kelvin + "0JFM",
"AQM1KZCML",
} {
func() {
defer func() {
if r := recover(); r != nil {
t.Errorf("Decode(%+q) panicked: %v", s, r)
}
}()
if _, _, err := bech32.Decode(s); err == nil {
t.Errorf("Decode(%+q) = nil error, want error", s)
}
}()
}
}