{"record":{"id":"ee1a0731f15df181","repo":"kubernetes/kubernetes","slug":"no-pem-block-headers-are-permitted","errorCode":null,"errorMessage":"no PEM block headers are permitted","messagePattern":"no PEM block headers are permitted","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apis/certificates/validation/validation.go","lineNumber":121,"sourceCode":"}\n\nfunc validateCertificate(pemData []byte) error {\n\tif len(pemData) == 0 {\n\t\treturn nil\n\t}\n\n\tblocks := 0\n\tfor {\n\t\tblock, remainingData := pem.Decode(pemData)\n\t\tif block == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tif block.Type != utilcert.CertificateBlockType {\n\t\t\treturn fmt.Errorf(\"only CERTIFICATE PEM blocks are allowed, found %q\", block.Type)\n\t\t}\n\t\tif len(block.Headers) != 0 {\n\t\t\treturn fmt.Errorf(\"no PEM block headers are permitted\")\n\t\t}\n\t\tblocks++\n\n\t\tcerts, err := x509.ParseCertificates(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(certs) == 0 {\n\t\t\treturn fmt.Errorf(\"found CERTIFICATE PEM block containing 0 certificates\")\n\t\t}\n\n\t\tpemData = remainingData\n\t}\n\n\tif blocks == 0 {\n\t\treturn fmt.Errorf(\"must contain at least one CERTIFICATE PEM block\")\n\t}\n","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/kubernetes/kubernetes/blob/b882c60b4023bdf09264c2d5d30a2cadebc240fb/pkg/apis/certificates/validation/validation.go#L103-L139","documentation":"Thrown by validateCertificate() when PEM-decoding a CSR's status.certificate field and a decoded PEM block contains non-empty Headers (e.g. Proc-Type, DEK-Info). Kubernetes requires the certificate PEM block to be a bare base64 body with the type 'CERTIFICATE' and zero headers, because encrypted or annotated PEM blocks are ambiguous and not X.509-trust-safe. The check fires during CSR status updates and ClusterTrustBundle-style certificate validation paths where allowArbitraryCertificate is false.","triggerScenarios":"Setting csr.Status.Certificate to a PEM blob whose block carries header lines (e.g. an encrypted private-key-style block mistakenly attached, or a PEM generated by an older OpenSSL that emits 'Proc-Type: 4,ENCRYPTED'). Reproduced by a status subresource update on a CertificateSigningRequest where the signer writes such a block.","commonSituations":"Piping a certificate through a tool that re-emits PEM with headers; copy-pasting a combined key+cert PEM into the certificate field; signer implementations that prepend annotations; upgrading Go's encoding/pem which now surfaces previously-tolerated headers.","solutions":["Regenerate the certificate PEM with a plain 'CERTIFICATE' block and no header lines: openssl x509 -in cert.pem -outform PEM removes annotations.","Strip any non-CERTIFICATE blocks (e.g. PRIVATE KEY, EC PARAMETERS) from the payload before writing status.certificate.","If using a custom signer, ensure it emits only RFC 7468 bare CERTIFICATE blocks with empty Headers.","Validate locally with encoding/pem and assert len(block.Headers)==0 && block.Type==\"CERTIFICATE\" before PATCHing the CSR status."],"exampleFix":"// before\nblock, _ := pem.Decode(pemData)\n// block.Headers = map[string]string{\"Proc-Type\": \"4,ENCRYPTED\"}\n\n// after - emit a clean block\npem.EncodeToMemory(&pem.Block{Type: \"CERTIFICATE\", Headers: map[string]string{}, Bytes: derCert})","handlingStrategy":"validation","validationCode":"import \"encoding/pem\"\n\nfunc validateCertPEM(pemData []byte) error {\n    for len(pemData) > 0 {\n        var block *pem.Block\n        block, pemData = pem.Decode(pemData)\n        if block == nil { break }\n        if block.Type != \"CERTIFICATE\" { return fmt.Errorf(\"bad block type %q\", block.Type) }\n        if len(block.Headers) != 0 { return fmt.Errorf(\"PEM block must have no headers\") }\n    }\n    return nil\n}","typeGuard":"func isCleanCertPEM(pemData []byte) bool {\n    block, _ := pem.Decode(pemData)\n    return block != nil && block.Type == \"CERTIFICATE\" && len(block.Headers) == 0\n}","tryCatchPattern":null,"preventionTips":["Always emit PEM via pem.EncodeToMemory with an empty Headers map.","Never paste encrypted PEM (Proc-Type/DEK-Info) into status.certificate.","Run `openssl x509 -in cert.pem -noout` as a pre-submit smoke test."],"tags":["kubernetes","certificates","pem","x509","validation"],"analyzedSha":"b882c60b4023bdf09264c2d5d30a2cadebc240fb","analyzedAt":"2026-08-07T04:07:48.144Z","schemaVersion":2},"datasetVersion":"2026-08-07T07:17:06.508Z"}