kgretzky/evilginx2 · critical
private key is corrupted
Error message
private key is corrupted
What it means
generateCertificates throws this when the cached PEM file exists but pem.Decode cannot extract a valid 'RSA PRIVATE KEY' block, meaning the stored key file is malformed or not PEM at all. Unlike a parse failure of a valid block (which returns the raw error), this is the case of no PEM data whatsoever.
Source
Thrown at core/certdb.go:107
// private key corrupted or not found, recreate and delete all public certificates
os.RemoveAll(filepath.Join(o.cache_dir, "*"))
key, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return fmt.Errorf("private key generation failed")
}
pkey = pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
})
err = ioutil.WriteFile(filepath.Join(o.cache_dir, "ca.key"), pkey, 0600)
if err != nil {
return err
}
} else {
block, _ := pem.Decode(pkey)
if block == nil {
return fmt.Errorf("private key is corrupted")
}
key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return err
}
}
ca_cert, err := ioutil.ReadFile(filepath.Join(o.cache_dir, "ca.crt"))
if err != nil {
notBefore := time.Now()
aYear := time.Duration(10*365*24) * time.Hour
notAfter := notBefore.Add(aYear)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return err
}View on GitHub (pinned to 4c0988a1d9)
Solutions
- Delete the corrupt ca.key in cache_dir and restart so the key is regenerated (public certs are also recreated)
- Restore a known-good ca.key file from backup
- Regenerate the whole cache_dir if site certificates are also suspect
- Ensure whatever manages the cache (sync/backup tools) preserves the file verbatim
Example fix
// before cp old-mixed-cache/ca.key ~/.evilginx/cache/ // wrong format file // after rm ~/.evilginx/cache/ca.key && rm -rf ~/.evilginx/cache/sites/* // let the tool regenerate
Defensive patterns
Strategy: validation
Validate before calling
data, err := os.ReadFile(filepath.Join(cacheDir, "ca.key"))
if err != nil || len(bytes.TrimSpace(data)) == 0 {
os.Remove(filepath.Join(cacheDir, "ca.key")) // let it regenerate
} else if blk, _ := pem.Decode(data); blk == nil || blk.Type != "RSA PRIVATE KEY" {
os.Remove(filepath.Join(cacheDir, "ca.key"))
} Type guard
func isPemRSAPrivateKey(data []byte) bool {
blk, _ := pem.Decode(data)
if blk == nil || blk.Type != "RSA PRIVATE KEY" { return false }
_, err := x509.ParsePKCS1PrivateKey(blk.Bytes)
return err == nil
} Try / catch
db, err := NewCertDb(cacheDir, "")
if err != nil {
if err.Error() == "private key is corrupted" {
os.Remove(filepath.Join(cacheDir, "ca.key"))
db, err = NewCertDb(cacheDir, "") // regenerate
}
if err != nil { log.Fatal(err) }
} Prevention
- Never hand-edit ca.key; treat the cache as tool-managed
- Check disk space before key writes to avoid truncated files
- Don't share or migrate cache dirs between different tool versions
- Back up the cache before maintenance so a good key can be restored
When it happens
Trigger: NewCertDb reads ca.key from cache_dir, the PEM block is nil — e.g. the file is empty, contains base64 without PEM armor, was truncated by an interrupted write, is a different key type (EC PRIVATE KEY), or was overwritten by another process.
Common situations: Disk-full or crash during key write; user manually editing/replacing ca.key; cache restored from backup with wrong format; mixing cache dirs between versions of the tool.
Related errors
- private key generation failed
- failed to get TLS certificate for: %s:%d error: %s
- failed to list certificates in directory '%s': %v
- failed to list certificate directory '%s': %v
AI-assisted analysis of kgretzky/evilginx2@4c0988a1d9 (2026-09-05).
Data as JSON: /api/errors/ea8de363ee170dab.
Report an issue: GitHub.