diff --git a/app/src/main/java/com/stevesoltys/seedvault/App.kt b/app/src/main/java/com/stevesoltys/seedvault/App.kt
index a51b5263..372c86fc 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/App.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/App.kt
@@ -2,6 +2,7 @@ package com.stevesoltys.seedvault
 
 import android.Manifest.permission.INTERACT_ACROSS_USERS_FULL
 import android.app.Application
+import android.app.backup.BackupManager
 import android.app.backup.BackupManager.PACKAGE_MANAGER_SENTINEL
 import android.app.backup.IBackupManager
 import android.content.Context
@@ -147,9 +148,10 @@ open class App : Application() {
 
 }
 
-const val MAGIC_PACKAGE_MANAGER = PACKAGE_MANAGER_SENTINEL
+const val MAGIC_PACKAGE_MANAGER: String = PACKAGE_MANAGER_SENTINEL
 const val ANCESTRAL_RECORD_KEY = "@ancestral_record@"
 const val GLOBAL_METADATA_KEY = "@meta@"
+const val ERROR_BACKUP_CANCELLED: Int = BackupManager.ERROR_BACKUP_CANCELLED
 
 // TODO this doesn't work for LineageOS as they do public debug builds
 fun isDebugBuild() = Build.TYPE == "userdebug"
diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsManager.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsManager.kt
index 786f5781..9584ffea 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsManager.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsManager.kt
@@ -166,6 +166,15 @@ class SettingsManager(private val context: Context) {
 
     fun isBackupEnabled(packageName: String) = !blacklistedApps.contains(packageName)
 
+    /**
+     * Disables backup for an app. Similar to [onAppBackupStatusChanged].
+     */
+    fun disableBackup(packageName: String) {
+        if (blacklistedApps.add(packageName)) {
+            prefs.edit().putStringSet(PREF_KEY_BACKUP_APP_BLACKLIST, blacklistedApps).apply()
+        }
+    }
+
     fun isStorageBackupEnabled() = prefs.getBoolean(PREF_KEY_BACKUP_STORAGE, false)
 
     @UiThread
diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt
index 30d93441..c507bd59 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt
@@ -1,6 +1,7 @@
 package com.stevesoltys.seedvault.ui.notification
 
 import android.app.backup.BackupProgress
+import android.app.backup.BackupTransport.AGENT_ERROR
 import android.app.backup.IBackupObserver
 import android.content.Context
 import android.content.pm.ApplicationInfo.FLAG_SYSTEM
@@ -8,9 +9,11 @@ import android.content.pm.PackageManager.NameNotFoundException
 import android.util.Log
 import android.util.Log.INFO
 import android.util.Log.isLoggable
+import com.stevesoltys.seedvault.ERROR_BACKUP_CANCELLED
 import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
 import com.stevesoltys.seedvault.R
 import com.stevesoltys.seedvault.metadata.MetadataManager
+import com.stevesoltys.seedvault.settings.SettingsManager
 import com.stevesoltys.seedvault.transport.backup.PackageService
 import com.stevesoltys.seedvault.worker.BackupRequester
 import org.koin.core.component.KoinComponent
@@ -27,11 +30,14 @@ internal class NotificationBackupObserver(
     private val nm: BackupNotificationManager by inject()
     private val metadataManager: MetadataManager by inject()
     private val packageService: PackageService by inject()
+    private val settingsManager: SettingsManager by inject()
     private var currentPackage: String? = null
     private var numPackages: Int = 0
     private var numPackagesToReport: Int = 0
     private var pmCounted: Boolean = false
 
+    private var errorPackageName: String? = null
+
     init {
         // Inform the notification manager that a backup has started
         // and inform about the expected numbers of apps.
@@ -86,6 +92,17 @@ internal class NotificationBackupObserver(
             // should only happen for MAGIC_PACKAGE_MANAGER, but better save than sorry
             Log.e(TAG, "Error getting ApplicationInfo: ", e)
         }
+
+        // Apps that get killed while interacting with their [BackupAgent] cancel the entire backup.
+        // In order to prevent them from DoSing us, we remember them here to auto-disable them.
+        // We noticed that the same app behavior can cause a status of
+        // either AGENT_ERROR or ERROR_BACKUP_CANCELLED, so we need to handle both.
+        errorPackageName = if (status == AGENT_ERROR || status == ERROR_BACKUP_CANCELLED) {
+            target
+        } else {
+            null // To not disable apps by mistake, we reset it when getting a new non-error result.
+        }
+
         // often [onResult] gets called right away without any [onUpdate] call
         showProgressNotification(target)
     }
@@ -98,6 +115,15 @@ internal class NotificationBackupObserver(
      *   as a whole failed.
      */
     override fun backupFinished(status: Int) {
+        if (status == ERROR_BACKUP_CANCELLED) {
+            val packageName = errorPackageName
+            if (packageName == null) {
+                Log.e(TAG, "Backup got cancelled, but there we have no culprit :(")
+            } else {
+                Log.w(TAG, "App $packageName misbehaved, will disable backup for it...")
+                settingsManager.disableBackup(packageName)
+            }
+        }
         if (backupRequester.requestNext()) {
             if (isLoggable(TAG, INFO)) {
                 Log.i(TAG, "Backup finished $numPackages/$requestedPackages. Status: $status")