CVE-2019-17596: How a Malformed Certificate Could Crash Your Go Program
In October 2019, the Go team released Go 1.12.11 and 1.13.2 to fix CVE-2019-17596, a denial-of-service vulnerability in crypto/dsa.
The bug was specific: a malformed DSA public key could make dsa.Verify panic instead of reporting an invalid signature. Because X.509 certificate verification can call dsa.Verify, an attacker could deliver the bad key inside a crafted certificate chain and crash some Go programs.
There was no remote code execution here. The impact was an unexpected process-ending panic in affected applications.
What went wrong in crypto/dsa
DSA verification performs modular arithmetic using values from the public key and signature. One step computes the modular inverse of the signature value s modulo the public key parameter Q.
Go’s big.Int.ModInverse returns nil when that inverse does not exist. A malicious public key could use a non-prime Q that made this happen. The vulnerable implementation passed the result into another multiplication without first checking it, which caused a nil-pointer panic.
The Go patch was small but important: check the result of ModInverse, and return false when it is nil. A malformed key is then treated as a failed verification rather than an exceptional condition that can take down the process.
This was not an elliptic-curve point-validation bug, despite the certificate-related symptoms. It affected DSA public keys and the crypto/dsa verification path.
Where an attacker could reach it
The official Go advisory called out several affected paths:
- A Go HTTPS client could panic while verifying a crafted certificate chain sent by a server.
- A TLS server that accepted and verified client certificates could encounter the same chain. However,
net/httpservers recovered this panic, so they were not crashed by it. - Calling
crypto/x509.(*CertificateRequest).CheckSignatureon a crafted certificate request could panic. - The old
golang.org/x/crypto/openpgp,otr, andsshpackages had reachable verification paths involving malformed DSA keys.
That is narrower than saying every Go TLS server or every ASN.1 parser was vulnerable. Exposure depended on whether untrusted input could reach DSA signature verification and whether the surrounding application recovered the panic.
Why parsing was not enough
The failure did not require crypto/x509.ParseCertificate itself to panic. A program could successfully parse certificate data and fail later while verifying a signature in the chain.
That distinction matters when you review security bugs. “We parsed the input” does not mean every value inside it is safe for later cryptographic operations. Verification code still has to reject invalid parameters without assuming they have the mathematical properties of a well-formed key.
How to check an old deployment
The fixed releases were Go 1.12.11 and Go 1.13.2. Both release lines have been unsupported for years, so the right response today is to rebuild with a currently supported Go release rather than upgrade only to those historical patch levels.
Check the toolchain installed on a machine with:
go version
For a Go binary built with module support, inspect its embedded build information with:
go version -m /path/to/your-binary
That output can tell you which Go version built the binary. Remember that updating the compiler on your workstation does not patch an already-built executable: rebuild and redeploy it.
You can also run govulncheck against source code or a compiled binary. It uses the Go vulnerability database and focuses its report on vulnerabilities that can affect the code being analyzed.
The broader lesson
CVE-2019-17596 came down to an unchecked result from a mathematical operation. The input was invalid, but invalid input should produce a normal verification failure—not a process-ending panic.
There are three useful habits to take from it:
- Keep the Go toolchain current, then rebuild and redeploy binaries after security updates.
- Treat all certificate, public-key, and signature data from a peer as untrusted until verification succeeds.
- When an API can signal failure with a sentinel such as
nil, handle that result before passing it deeper into the program.
The standard library fix made DSA verification fail safely. For application teams, the durable protection is less exotic: maintain supported toolchains, know which binaries are actually deployed, and make vulnerability scanning part of routine releases.