diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index a1f4c67f331899d045dcbe47fec22ac552516368..7bb985f857b46903ab63dbc878de7f97f124a7de 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -447,7 +447,8 @@ EventStore::edits(const std::string &event_id)
     auto event_ids = cache::client()->relatedEvents(room_id_, event_id);
 
     auto original_event = get(event_id, "", false, false);
-    if (!original_event)
+    if (!original_event ||
+        std::holds_alternative<mtx::events::RoomEvent<mtx::events::msg::Redacted>>(*original_event))
         return {};
 
     auto original_sender    = mtx::accessors::sender(*original_event);
diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h
index 9b857dcfacf5214ed971261fd31479e91e5417f1..1730f9fdd092f2672366a543ca48e751fa80a54f 100644
--- a/src/timeline/EventStore.h
+++ b/src/timeline/EventStore.h
@@ -77,6 +77,7 @@ public:
     mtx::events::collections::TimelineEvents *get(int idx, bool decrypt = true);
 
     QVariantList reactions(const std::string &event_id);
+    std::vector<mtx::events::collections::TimelineEvents> edits(const std::string &event_id);
     olm::DecryptionErrorCode decryptionError(std::string id);
     void requestSession(const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &ev,
                         bool manual);
@@ -120,7 +121,6 @@ public slots:
     void enableKeyRequests(bool suppressKeyRequests_);
 
 private:
-    std::vector<mtx::events::collections::TimelineEvents> edits(const std::string &event_id);
     olm::DecryptionResult *decryptEvent(
       const IdIndex &idx,
       const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &e);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 0e5ce510b1ea80258d676bdfe635a02d5e1f9f57..aa7a68f30ea636fb9995e0459f49982719675ee0 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -344,6 +344,19 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
       [](const QString &msg) { emit ChatPage::instance()->showNotification(msg); },
       Qt::QueuedConnection);
 
+    connect(this, &TimelineModel::dataAtIdChanged, this, [this](QString id) {
+        relatedEventCacheBuster++;
+
+        auto idx = idToIndex(id);
+        if (idx != -1) {
+            auto pos = index(idx);
+            nhlog::ui()->debug("data changed at {}", id.toStdString());
+            emit dataChanged(pos, pos);
+        } else {
+            nhlog::ui()->debug("id not found {}", id.toStdString());
+        }
+    });
+
     connect(this,
             &TimelineModel::newMessageToSend,
             this,
@@ -1095,7 +1108,8 @@ TimelineModel::showReadReceipts(QString id)
 void
 TimelineModel::redactEvent(QString id)
 {
-    if (!id.isEmpty())
+    if (!id.isEmpty()) {
+        auto edits = events.edits(id.toStdString());
         http::client()->redact_event(
           room_id_.toStdString(),
           id.toStdString(),
@@ -1106,8 +1120,26 @@ TimelineModel::redactEvent(QString id)
                   return;
               }
 
-              emit eventRedacted(id);
+              emit dataAtIdChanged(id);
           });
+
+        // redact all edits to prevent leaks
+        for (const auto &e : edits) {
+            auto id_ = mtx::accessors::event_id(e);
+            http::client()->redact_event(
+              room_id_.toStdString(),
+              id_,
+              [this, id, id_](const mtx::responses::EventId &, mtx::http::RequestErr err) {
+                  if (err) {
+                      emit redactionFailed(tr("Message redaction failed: %1")
+                                             .arg(QString::fromStdString(err->matrix_error.error)));
+                      return;
+                  }
+
+                  emit dataAtIdChanged(id);
+              });
+        }
+    }
 }
 
 int
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index f16529e21790157e67a9070be24c85f61dc05f14..af067476035d329b000eae8c069293dbdcf1a5e3 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -367,9 +367,9 @@ private slots:
     void scrollTimerEvent();
 
 signals:
+    void dataAtIdChanged(QString id);
     void currentIndexChanged(int index);
     void redactionFailed(QString id);
-    void eventRedacted(QString id);
     void mediaCached(QString mxcUrl, QString cacheUrl);
     void newEncryptedImage(mtx::crypto::EncryptedFile encryptionInfo);
     void typingUsersChanged(std::vector<QString> users);