diff --git a/src/encrypt.rs b/src/encrypt.rs
index d108cf37d7cb0bb59e2660a583a4ef7f4f6c6400..eba4f4b4b68b60382eeef28d29097a05699f692d 100644
--- a/src/encrypt.rs
+++ b/src/encrypt.rs
@@ -59,6 +59,11 @@ impl KeyState {
         }
     }
 
+    pub fn is_cleartext(&self) -> bool {
+        matches!(self.keys.enc, EncKey::NoCipher)
+            || matches!(self.keys.dec, DecKey::NoCipher)
+    }
+
     /// Updates with new keys, keeping the same sequence numbers
     pub fn rekey(&mut self, keys: Keys) {
         self.keys = keys
diff --git a/src/traffic.rs b/src/traffic.rs
index f480b80b43e095dcbad886e3c839fb267a811410..ec6f93cf40bb7120a9812d702ed9224ef02fc45d 100644
--- a/src/traffic.rs
+++ b/src/traffic.rs
@@ -290,6 +290,16 @@ impl<'a> TrafOut<'a> {
             TxState::Write { idx, len } => (idx, len),
         };
 
+        // Sanity check
+        match p.category() {
+            packets::Category::All | packets::Category::Kex => (), // OK cleartext
+            _ => {
+                if keys.is_cleartext() {
+                    return Error::bug_msg("send cleartext")
+                }
+            }
+        }
+
         // Use the remainder of our buffer to write the packet. Payload starts
         // after the length and padding bytes which get filled by encrypt()
         let wbuf = &mut self.buf[len..];