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

  1. Delete the corrupt ca.key in cache_dir and restart so the key is regenerated (public certs are also recreated)
  2. Restore a known-good ca.key file from backup
  3. Regenerate the whole cache_dir if site certificates are also suspect
  4. 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

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


AI-assisted analysis of kgretzky/evilginx2@4c0988a1d9 (2026-09-05). Data as JSON: /api/errors/ea8de363ee170dab. Report an issue: GitHub.