{"record":{"id":"248cdc2a61de20ac","repo":"crowdsecurity/crowdsec","slug":"certificate-revoked-by-crl","errorCode":null,"errorMessage":"certificate revoked by CRL","messagePattern":"certificate revoked by CRL","errorType":"http","errorClass":null,"httpStatus":401,"severity":"critical","filePath":"pkg/apiserver/middlewares/v1/tls_auth.go","lineNumber":62,"sourceCode":"\n\t// starting from the root CA and moving towards the leaf certificate,\n\t// check for revocation of intermediates too\n\tfor i := len(chain) - 1; i > 0; i-- {\n\t\tcert := chain[i-1]\n\t\tissuer := chain[i]\n\n\t\trevokedByOCSP, checkedByOCSP := ta.ocspChecker.isRevokedBy(ctx, cert, issuer)\n\t\tcouldCheck = couldCheck && checkedByOCSP\n\n\t\tif revokedByOCSP && checkedByOCSP {\n\t\t\treturn errors.New(\"certificate revoked by OCSP\"), couldCheck\n\t\t}\n\n\t\trevokedByCRL, checkedByCRL := ta.crlChecker.isRevokedBy(cert, issuer)\n\t\tcouldCheck = couldCheck && checkedByCRL\n\n\t\tif revokedByCRL && checkedByCRL {\n\t\t\treturn errors.New(\"certificate revoked by CRL\"), couldCheck\n\t\t}\n\t}\n\n\treturn nil, couldCheck\n}\n\nfunc (ta *TLSAuth) setAllowedOu(allowedOus []string) error {\n\tuniqueOUs := make(map[string]struct{})\n\n\tfor _, ou := range allowedOus {\n\t\t// disallow empty ou\n\t\tif ou == \"\" {\n\t\t\treturn errors.New(\"allowed_ou configuration contains invalid empty string\")\n\t\t}\n\n\t\tif _, exists := uniqueOUs[ou]; exists {\n\t\t\tta.logger.Warningf(\"dropping duplicate ou %s\", ou)\n\t\t\tcontinue","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiserver/middlewares/v1/tls_auth.go#L44-L80","documentation":"Same revocation path as the OCSP case, but the certificate was found on a Certificate Revocation List. The CRL checker reports the certificate as revoked by its issuer, so ValidateCert rejects the mTLS client.","triggerScenarios":"ValidateCert -> checkRevocationPath when ta.crlChecker.isRevokedBy(cert, issuer) returns revoked=true and checked=true for any cert in the client chain.","commonSituations":"Client certificate serial was added to the CA's CRL (expired bouncer, manually revoked cert); CRL distribution points configured and the CRL is fresh; client still using an old cert.","solutions":["Issue and configure a new client certificate","Check the CRL to confirm the revocation and its reason","Update the client to use the new certificate/keystore","If the CA revoked in error, remove the serial from the CRL and refresh it"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// check the cert serial against the current CRL before deploying\nfor _, s := range crl.RevokedCertificateSerials {\n    if s.Cmp(cert.SerialNumber) == 0 { reissueCert() }\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, errRevoked) || strings.Contains(err.Error(), \"revoked by CRL\") {\n    reissueAndReenroll() // do not retry with the same cert\n}","preventionTips":["Keep CRLs fresh on the server and distribution points reachable","Replace client certs whenever the CA revokes a serial","Track certificate inventory so stale certs are cleaned up"],"tags":["tls","mtls","crl","revocation","certificate"],"backgroundTag":"certificate-revoked","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}