google / google/certificate-transparency-go
SSRF via unvalidated AIA/CRL URLs in certificate extensions (sctcheck, certcheck, crlcheck, fixchain)
- Dominant language
- Go
- Stars
- 1.2k
- Forks
- 322
- Avg merge
- 3d 4h
- Merged PRs (30d)
- 5
Description
## Summary
The `certificate-transparency-go` operator tooling (`sctcheck`, `certcheck`, `crlcheck`, and the `fixchain` preloader) fetches URLs from certificate extensions (AIA CA Issuers, CRL Distribution Points) without any SSRF protection.
## Vulnerable Code
**Root cause: `x509util/files.go:97-115` — `GetIssuer()` fetches AIA URL with no validation**
```go
func GetIssuer(cert *x509.Certificate, client *http.Client) (*x509.Certificate, error) {
issuerURL := cert.IssuingCertificateURL[0] // raw string from cert's AIA extension
rsp, err := client.Get(issuerURL) // HTTP GET with no scheme/host/IP validation
body, err := io.ReadAll(rsp.Body) // no response size limit — OOM possible
```
**Same vulnerability in five additional callsites:**
1. `ctutil/sctcheck/sctcheck.go:131` — triggers `GetIssuer()` during SCT checking
2. `x509util/crlcheck/crlcheck.go:170-174` — directly calls `client.Get(crldp)` on CRL Distribution Points
3. `x509util/files.go:48-56` — `ReadPossiblePEMURL` uses bare `http.Get()` with no timeout
4. `x509util/certcheck/certcheck.go:226-227` — `checkRevocation()` calls `ReadPossiblePEMURL` on CRL Distribution Points
5. `fixchain/url_cache.go:67` — `fixchain` preloader calls `client.Get(url)` on AIA URLs from every cert in a CT log
Additionally, `InsecureSkipVerify: true` is set in tooling (`sctcheck`, `certcheck`), disabling TLS certificate validation.
## Attack Scenario
An attacker submits a certificate with an AIA CA Issuers URL of `http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token` to a CT log operator who then runs `sctcheck`, `certcheck --check_revocation`, or `crlcheck`. The tool makes an outbound HTTP request to the GCP instance metadata endpoint from the operator's cloud VM.
## Suggested Fix
Add URL validation before fetching AIA/CRL URLs: reject private IP ranges, cloud metadata endpoints, and loopback addresses. Add response size limits to `io.ReadAll` calls. Add timeouts to `http.Get` calls.
Contributor guide
Research direction
Start with x509util/files.go:48-56 and 97-115, then trace the callers in sctutil/sctcheck/sctcheck.go, x509util/crlcheck/crlcheck.go, x509util/certcheck/certcheck.go, and fixchain/url_cache.go. Done means AIA and CRL URL fetches validate destinations, responses are size-limited, HTTP fetches have timeouts, and the tooling's TLS behavior is reviewed without leaving the listed callsites exposed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100