diff --git a/src/channel.rs b/src/channel.rs
index 3ca27c063ab5c7cd7bc6804d9637cdc4c2cb2fa2..c6349eac4a7f811a19b7aa0ce61caec88783c79f 100644
--- a/src/channel.rs
+++ b/src/channel.rs
@@ -337,9 +337,9 @@ impl Channels {
         packet: Packet<'_>,
         s: &mut TrafSend<'_, '_>,
         b: &mut Behaviour<'_>,
-    ) -> Result<Dispatched> {
+    ) -> Result<Option<DataIn>> {
         trace!("chan dispatch");
-        let mut disp = Dispatched(None);
+        let mut data_in = None;
         match packet {
             Packet::ChannelOpen(p) => {
                 self.dispatch_open(&p, s, b)?;
@@ -400,7 +400,7 @@ impl Channels {
                     offset: ChannelData::DATA_OFFSET,
                     len: p.data.0.len(),
                 };
-                disp = Dispatched(Some(di));
+                data_in = Some(di);
             }
             Packet::ChannelDataExt(p) => {
                 self.get(p.num)?;
@@ -436,7 +436,7 @@ impl Channels {
             }
             _ => Error::bug_msg("unreachable")?,
         };
-        Ok(disp)
+        Ok(data_in)
     }
 
     /// Incoming packet handling
@@ -447,17 +447,17 @@ impl Channels {
         packet: Packet<'_>,
         s: &mut TrafSend<'_, '_>,
         b: &mut Behaviour<'_>,
-    ) -> Result<Dispatched> {
+    ) -> Result<Option<DataIn>> {
         let r = self.dispatch_inner(packet, s, b).await;
 
         match r {
             Err(Error::BadChannel) => {
                 warn!("Ignoring bad channel number");
-                Ok(Dispatched(None))
+                Ok(None)
             }
             // TODO: close channel on error? or on SSHProtoError?
             Err(any) => Err(any),
-            Ok(disp) => Ok(disp),
+            Ok(data_in) => Ok(data_in),
         }
     }
 }
diff --git a/src/conn.rs b/src/conn.rs
index 2edbeef646e111564ef222d196ff43578e1b01ee..954f771d623cb47d401a70546fcf9eb01ceb502a 100644
--- a/src/conn.rs
+++ b/src/conn.rs
@@ -83,7 +83,12 @@ enum ConnState {
     // Cleanup ??
 }
 
-pub(crate) struct Dispatched(pub Option<channel::DataIn>);
+#[derive(Default)]
+pub(crate) struct Dispatched {
+    pub data_in: Option<channel::DataIn>,
+    /// set for sensitive payloads such as password auth
+    pub zeroize_payload: bool,
+}
 
 impl Conn {
     pub fn new_client() -> Result<Self> {
@@ -174,7 +179,7 @@ impl Conn {
             Err(Error::UnknownPacket { number }) => {
                 trace!("Unimplemented packet type {number}");
                 s.send(packets::Unimplemented { seq })?;
-                Ok(Dispatched(None))
+                Ok(Dispatched::default())
             }
             Err(e) => {
                 trace!("Error decoding packet: {e} {:#?}", payload.hex_dump());
@@ -223,7 +228,7 @@ impl Conn {
     ) -> Result<Dispatched, Error> {
         // TODO: perhaps could consolidate packet client vs server checks
         trace!("Incoming {packet:#?}");
-        let mut disp = Dispatched(None);
+        let mut disp = Dispatched::default();
 
         self.check_packet(&packet)?;
 
@@ -331,6 +336,7 @@ impl Conn {
             }
             Packet::UserauthRequest(p) => {
                 if let ClientServer::Server(serv) = &mut self.cliserv {
+                    disp.zeroize_payload = true;
                     let sess_id = self.sess_id.as_ref().trap()?;
                     let success = serv.auth.request(p, sess_id, s, b.server()?)?;
                     if success {
@@ -394,7 +400,7 @@ impl Conn {
             | Packet::ChannelFailure(_)
             // TODO: maybe needs a conn or cliserv argument.
             => {
-                disp = self.channels.dispatch(packet, s, b).await?;
+                disp.data_in = self.channels.dispatch(packet, s, b).await?;
            }
         };
         Ok(disp)
diff --git a/src/runner.rs b/src/runner.rs
index 8b505adac87a83c36ff22ed95761f1cd41a9f900..5193fdb1ea669ec75d22898f9bdaf6c5185d54f1 100644
--- a/src/runner.rs
+++ b/src/runner.rs
@@ -94,14 +94,14 @@ impl<'a> Runner<'a> {
         if let Some((payload, seq)) = self.traf_in.payload() {
             let d = self.conn.handle_payload(payload, seq, &mut s, behaviour).await?;
 
-            if let Some(d) = d.0 {
+            if let Some(data_in) = d.data_in {
                 // incoming channel data, we haven't finished with payload
                 trace!("handle_payload chan input");
-                self.traf_in.set_channel_input(d)?;
+                self.traf_in.set_channel_input(data_in)?;
             } else {
                 // other packets have been completed
                 trace!("handle_payload done");
-                self.traf_in.done_payload()?;
+                self.traf_in.done_payload(d.zeroize_payload)?;
             }
         }
 
diff --git a/src/traffic.rs b/src/traffic.rs
index f0a4ed8605827861a1eeb9490a81452af9b06632..850524ccc6fd5325289fbdeb9e526c0c095b1d45 100644
--- a/src/traffic.rs
+++ b/src/traffic.rs
@@ -4,6 +4,8 @@ use {
     log::{debug, error, info, log, trace, warn},
 };
 
+use zeroize::Zeroize;
+
 use crate::encrypt::KeyState;
 use crate::encrypt::{SSH_LENGTH_SIZE, SSH_PAYLOAD_START};
 use crate::ident::RemoteVersion;
@@ -128,9 +130,12 @@ impl<'a> TrafIn<'a> {
     }
 
     /// Called when `payload()` and `payload_reborrow()` are complete.
-    pub(crate) fn done_payload(&mut self) -> Result<(), Error> {
+    pub(crate) fn done_payload(&mut self, zeroize: bool) -> Result<(), Error> {
         match self.state {
-            RxState::InPayload { .. } => {
+            RxState::InPayload { len, .. } => {
+                if zeroize {
+                    self.buf[SSH_PAYLOAD_START..SSH_PAYLOAD_START + len].zeroize();
+                }
                 self.state = RxState::Idle;
                 Ok(())
             }