diff --git a/prdoc/pr_6963.prdoc b/prdoc/pr_6963.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..7657349277b373ea59855b4c7393c9109adf4664
--- /dev/null
+++ b/prdoc/pr_6963.prdoc
@@ -0,0 +1,10 @@
+title: 'grandpa: Ensure `WarpProof` stays in its limits'
+doc:
+- audience: Node Dev
+  description: |-
+    There was the chance that a `WarpProof` was bigger than the maximum warp sync proof size. This could have happened when inserting the last justification, which then may pushed the total proof size above the maximum. The solution is simply to ensure that the last justfication also fits into the limits.
+
+    Close: https://github.com/paritytech/polkadot-sdk/issues/6957
+crates:
+- name: sc-consensus-grandpa
+  bump: patch
diff --git a/substrate/client/consensus/grandpa/src/warp_proof.rs b/substrate/client/consensus/grandpa/src/warp_proof.rs
index a79581b1e9f13092b917b64a443af31aa7cd8a27..ada3a45e186e0a48de5f6b1b7e912df7dd5a4c3a 100644
--- a/substrate/client/consensus/grandpa/src/warp_proof.rs
+++ b/substrate/client/consensus/grandpa/src/warp_proof.rs
@@ -174,10 +174,20 @@ impl<Block: BlockT> WarpSyncProof<Block> {
 				let header = blockchain.header(latest_justification.target().1)?
 					.expect("header hash corresponds to a justification in db; must exist in db as well; qed.");
 
-				proofs.push(WarpSyncFragment { header, justification: latest_justification })
+				let proof = WarpSyncFragment { header, justification: latest_justification };
+
+				// Check for the limit. We remove some bytes from the maximum size, because we're
+				// only counting the size of the `WarpSyncFragment`s. The extra margin is here
+				// to leave room for rest of the data (the size of the `Vec` and the boolean).
+				if proofs_encoded_len + proof.encoded_size() >= MAX_WARP_SYNC_PROOF_SIZE - 50 {
+					false
+				} else {
+					proofs.push(proof);
+					true
+				}
+			} else {
+				true
 			}
-
-			true
 		};
 
 		let final_outcome = WarpSyncProof { proofs, is_finished };