diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/TaskController.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/TaskController.kt
index 932fb9bebc875c253a4e8bbae26b8bbbb5f91c7c..b7cc4ca6ebdcdff2468b3fd006a81272cd82d51b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/TaskController.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/task/TaskController.kt
@@ -123,7 +123,6 @@ class TaskController @Inject constructor(
 
     private suspend fun processMap() = internalTaskData.updateSafely {
         Timber.tag(TAG).d("Processing task data (count=%d)", size)
-        Timber.tag(TAG).v("Tasks before processing: %s", this.values)
 
         // Procress all unprocessed finished tasks
         procressFinishedTasks(this).let {
@@ -137,7 +136,19 @@ class TaskController @Inject constructor(
             this.putAll(it)
         }
 
-        Timber.tag(TAG).v("Tasks after processing: %s", this.values)
+        if (size > TASK_HISTORY_LIMIT) {
+            Timber.v("Enforcing history limits (%d), need to remove %d.", TASK_HISTORY_LIMIT, size - TASK_HISTORY_LIMIT)
+            values
+                .filter { it.isFinished }
+                .sortedBy { it.finishedAt }
+                .take(size - TASK_HISTORY_LIMIT)
+                .forEach {
+                    Timber.v("Removing from history: %s", get(it.id))
+                    remove(it.id)
+                }
+        }
+
+        Timber.tag(TAG).v("Tasks after processing (count=%d):\n%s", size, values.joinToString("\n"))
     }
 
     private fun procressFinishedTasks(data: Map<UUID, InternalTaskState>): Map<UUID, InternalTaskState> {
@@ -178,9 +189,9 @@ class TaskController @Inject constructor(
                         it.id != state.id
                 }
                 Timber.tag(TAG).d("Task has %d siblings", siblingTasks.size)
-                Timber.tag(TAG).v(
-                    "Sibling are:\n%s", siblingTasks.joinToString("\n")
-                )
+                if (siblingTasks.isNotEmpty()) {
+                    Timber.tag(TAG).v("Sibling are:\n%s", siblingTasks.joinToString("\n"))
+                }
 
                 // Handle collision behavior for tasks of same type
                 when {
@@ -237,5 +248,6 @@ class TaskController @Inject constructor(
 
     companion object {
         private const val TAG = "TaskController"
+        private const val TASK_HISTORY_LIMIT = 50
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/TaskControllerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/TaskControllerTest.kt
index 581eab4dc2df49394919ab0679391f98f230333f..d84078cf9b2bd447d63555b5c44d2b6ecb197b5e 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/TaskControllerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/task/TaskControllerTest.kt
@@ -539,4 +539,44 @@ class TaskControllerTest : BaseIOTest() {
 
         instance.close()
     }
+
+    @Test
+    fun `old tasks are pruned from history`() = runBlockingTest {
+        val instance = createInstance(scope = this)
+
+        val expectedFiles = mutableListOf<File>()
+
+        repeat(100) {
+            val arguments = QueueingTask.Arguments(
+                delay = 5,
+                values = listOf("TestText"),
+                path = File(testDir, UUID.randomUUID().toString())
+            )
+            expectedFiles.add(arguments.path)
+
+            val request = DefaultTaskRequest(type = QueueingTask::class, arguments = arguments)
+            instance.submit(request)
+            delay(5)
+        }
+
+        this.advanceUntilIdle()
+
+        expectedFiles.forEach {
+            it.exists() shouldBe true
+        }
+
+        val taskHistory = instance.tasks.first()
+        taskHistory.size shouldBe 50
+        expectedFiles.size shouldBe 100
+
+        val sortedHistory = taskHistory.sortedBy { it.taskState.startedAt }.apply {
+            first().taskState.startedAt!!.isBefore(last().taskState.startedAt) shouldBe true
+        }
+
+        expectedFiles.subList(50, 100) shouldBe sortedHistory.map {
+            (it.taskState.request.arguments as QueueingTask.Arguments).path
+        }
+
+        instance.close()
+    }
 }