{"record":{"id":"f4b49dfd4444db14","repo":"hyperledger/fabric","slug":"malformed-orderer-metadata-in-signature","errorCode":null,"errorMessage":"malformed orderer metadata in signature","messagePattern":"malformed orderer metadata in signature","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/verifier.go","lineNumber":405,"sourceCode":"\t\t\tbase64.StdEncoding.EncodeToString(sig.BlockHeader))\n\t\treturn errors.Errorf(\"mismatched block header\")\n\t}\n\n\t// Ensure signature header matches the identity\n\tsigHdr := &cb.IdentifierHeader{}\n\tif err := proto.Unmarshal(sig.IdentifierHeader, sigHdr); err != nil {\n\t\treturn errors.Wrap(err, \"malformed signature header\")\n\t}\n\tif identityID != uint64(sigHdr.Identifier) {\n\t\tv.Logger.Warnf(\"Expected identity %d but got %d\", identityID,\n\t\t\tsigHdr.Identifier)\n\t\treturn errors.Errorf(\"identity in signature header does not match expected identity\")\n\t}\n\n\t// Ensure orderer block metadata's consenter MD matches the proposal\n\tordererMD := &cb.OrdererBlockMetadata{}\n\tif err := proto.Unmarshal(sig.OrdererBlockMetadata, ordererMD); err != nil {\n\t\treturn errors.Wrap(err, \"malformed orderer metadata in signature\")\n\t}\n\n\tif !bytes.Equal(ordererMD.ConsenterMetadata, prop.Metadata) {\n\t\tv.Logger.Warnf(\"Expected consenter metadata %s but got %s in proposal\",\n\t\t\tbase64.StdEncoding.EncodeToString(ordererMD.ConsenterMetadata), base64.StdEncoding.EncodeToString(prop.Metadata))\n\t\treturn errors.Errorf(\"consenter metadata in OrdererBlockMetadata doesn't match proposal\")\n\t}\n\n\tblock, err := ProposalToBlock(prop)\n\tif err != nil {\n\t\tv.Logger.Warnf(\"got malformed proposal: %v\", err)\n\t\treturn err\n\t}\n\n\t// Ensure Metadata slice is of the right size\n\tif len(block.Metadata.Metadata) != len(cb.BlockMetadataIndex_name) {\n\t\treturn errors.Errorf(\"block metadata is of size %d but should be of size %d\",\n\t\t\tlen(block.Metadata.Metadata), len(cb.BlockMetadataIndex_name))","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/verifier.go#L387-L423","documentation":"The consenter metadata (opaque consensus-related bytes) inside the signature's OrdererBlockMetadata must byte-match the metadata attached to the proposal. This error means the signature was computed over different consenter metadata than what the proposal carries, so the signature cannot be bound to this proposal.","triggerScenarios":"VerifyConsenterSig -> verifySignatureIsBoundToProposal: bytes.Equal(ordererMD.ConsenterMetadata, prop.Metadata) is false — the OrdererBlockMetadata in the signature holds different consenter metadata bytes than prop.Metadata. Triggered by replayed signatures from another proposal or by a signing node that embedded different consenter metadata (e.g. different leader/rotation info) than the proposer.","commonSituations":"Mixed Fabric versions encoding consenter metadata differently; a node with a stale view producing metadata from a previous leader rotation; replayed or cross-proposal signature reuse; message corruption.","solutions":["Drop the mismatched signature and re-request signature collection for the current proposal.","Upgrade all consenters to the same Fabric version to ensure identical consenter metadata encoding.","Force a view change so a fresh proposal with consistent consenter metadata is proposed and signed.","If persistent, enable BFT debug logs and compare the base64 metadata from the log line to identify which field differs."],"exampleFix":"// before\nordererMD.ConsenterMetadata = \"old-rotation-md\"; prop.Metadata = \"new-rotation-md\" -> error\n// after: signer embeds proposal's metadata verbatim\nordererMD.ConsenterMetadata = prop.Metadata","handlingStrategy":"validation","validationCode":"if !bytes.Equal(ordererMD.GetConsenterMetadata(), prop.Metadata) {\n    return errors.New(\"signature consenter metadata differs from proposal; request fresh signature\")\n}","typeGuard":null,"tryCatchPattern":"err := verifier.VerifyConsenterSig(sig, id)\nif err != nil && strings.Contains(err.Error(), \"doesn't match proposal\") {\n    // drop signature, trigger re-proposal/view change\n}","preventionTips":["Signers must embed the proposal's metadata bytes verbatim","Upgrade stragglers so consenter metadata encoding is uniform","After leader rotation, require fresh proposals before signature collection"],"tags":["hyperledger-fabric","smartbft","consenter-metadata","signature-verification"],"backgroundTag":"consenter-metadata-mismatch","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}