diff --git a/Corona-Warn-App/config/detekt.yml b/Corona-Warn-App/config/detekt.yml
index 1a5fd4a6d97d1f13e143788f0f59c9d3b2bdc5cc..2555aa687375ea096032184e62adfedd4ce03604 100644
--- a/Corona-Warn-App/config/detekt.yml
+++ b/Corona-Warn-App/config/detekt.yml
@@ -572,7 +572,7 @@ style:
     excludedFunctions: 'equals'
     excludeLabeled: false
     excludeReturnFromLambda: true
-    excludeGuardClauses: false
+    excludeGuardClauses: true
   SafeCast:
     active: true
   SerialVersionUIDInSerializableClass:
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/QRScanResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/QRScanResult.kt
new file mode 100644
index 0000000000000000000000000000000000000000..783ec13a29ac5895765b53c0de7e47b19843807b
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/QRScanResult.kt
@@ -0,0 +1,32 @@
+package de.rki.coronawarnapp.service.submission
+
+import java.util.regex.Pattern
+
+data class QRScanResult(val rawResult: String) {
+
+    val isValid: Boolean
+        get() = guid != null
+    val guid: String? by lazy { extractGUID(rawResult) }
+
+    private fun extractGUID(rawResult: String): String? {
+        if (rawResult.length > MAX_QR_CODE_LENGTH) return null
+        if (rawResult.count { it == GUID_SEPARATOR } != 1) return null
+        if (!QR_CODE_REGEX.toRegex().matches(rawResult)) return null
+
+        val potentialGUID = rawResult.substringAfterLast(GUID_SEPARATOR, "")
+        if (potentialGUID.isBlank() || potentialGUID.length > MAX_GUID_LENGTH) return null
+
+        return potentialGUID
+    }
+
+    companion object {
+        // regex pattern for scanned QR code URL
+        val QR_CODE_REGEX: Pattern = Pattern.compile(
+            "^((^https:\\/{2}localhost)(\\/\\?)[A-Fa-f0-9]{6}" +
+                    "[-][A-Fa-f0-9]{8}[-][A-Fa-f0-9]{4}[-][A-Fa-f0-9]{4}[-][A-Fa-f0-9]{4}[-][A-Fa-f0-9]{12})\$"
+        )
+        const val GUID_SEPARATOR = '?'
+        const val MAX_QR_CODE_LENGTH = 150
+        const val MAX_GUID_LENGTH = 80
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt
index 4ab4045084e1622f85f212ac4909f25a604ae984..43de684e2e6535aa2253b3198c82022b8af88991 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionConstants.kt
@@ -14,10 +14,6 @@ object SubmissionConstants {
     val TEST_RESULT_URL = "$VERSIONED_VERIFICATION_CDN_URL/$TEST_RESULT"
     val TAN_REQUEST_URL = "$VERSIONED_VERIFICATION_CDN_URL/$TAN"
 
-    const val MAX_QR_CODE_LENGTH = 150
-    const val MAX_GUID_LENGTH = 80
-    const val GUID_SEPARATOR = '?'
-
     const val SERVER_ERROR_CODE_400 = 400
 
     const val EMPTY_HEADER = ""
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
index defce20ed3566931a323c6756791038c801482da..e33668fa5ddabfdda14f8a7564555a5fff992786 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/submission/SubmissionService.kt
@@ -65,19 +65,10 @@ object SubmissionService {
     }
 
     fun containsValidGUID(scanResult: String): Boolean {
-        if (scanResult.length > SubmissionConstants.MAX_QR_CODE_LENGTH ||
-            scanResult.count { it == SubmissionConstants.GUID_SEPARATOR } != 1
-        )
-            return false
-
-        val potentialGUID = extractGUID(scanResult)
-
-        return !(potentialGUID.isEmpty() || potentialGUID.length > SubmissionConstants.MAX_GUID_LENGTH)
+        val scanResult = QRScanResult(scanResult)
+        return scanResult.isValid
     }
 
-    fun extractGUID(scanResult: String): String =
-        scanResult.substringAfterLast(SubmissionConstants.GUID_SEPARATOR, "")
-
     fun storeTestGUID(guid: String) = LocalData.testGUID(guid)
 
     fun deleteTestGUID() {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
index 2fced7642eda4289f66510d0df15fe43d6ed74e0..c5f670cb06796888458824bdbeb98cc15d6bee50 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt
@@ -9,6 +9,7 @@ import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.TransactionException
 import de.rki.coronawarnapp.exception.http.CwaWebException
 import de.rki.coronawarnapp.exception.reporting.report
+import de.rki.coronawarnapp.service.submission.QRScanResult
 import de.rki.coronawarnapp.service.submission.SubmissionService
 import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.storage.SubmissionRepository
@@ -98,10 +99,10 @@ class SubmissionViewModel : ViewModel() {
             _uiStateError
         )
 
-    fun validateAndStoreTestGUID(scanResult: String) {
-        if (SubmissionService.containsValidGUID(scanResult)) {
-            val guid = SubmissionService.extractGUID(scanResult)
-            SubmissionService.storeTestGUID(guid)
+    fun validateAndStoreTestGUID(rawResult: String) {
+        val scanResult = QRScanResult(rawResult)
+        if (scanResult.isValid) {
+            SubmissionService.storeTestGUID(scanResult.guid!!)
             _scanStatus.value = Event(ScanStatus.SUCCESS)
         } else {
             _scanStatus.value = Event(ScanStatus.INVALID)
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2f7e78179372d2c27c2d55694274a65f0a44486b
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/ScanResultTest.kt
@@ -0,0 +1,54 @@
+package de.rki.coronawarnapp.service.submission
+
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.mockkObject
+import org.junit.Before
+import org.junit.Test
+
+class ScanResultTest {
+    private val guid = "123456-12345678-1234-4DA7-B166-B86D85475064"
+
+    @MockK
+    private lateinit var scanResult: QRScanResult
+
+    @Before
+    fun setUp() {
+        MockKAnnotations.init(this)
+        mockkObject(scanResult)
+        every { scanResult.isValid } returns false
+    }
+
+    @Test
+    fun containsValidGUID() {
+        //valid test
+        scanResult = QRScanResult("https://localhost/?$guid")
+        scanResult.isValid shouldBe true
+
+        // more invalid tests checks
+        scanResult = QRScanResult("http://localhost/?$guid")
+        scanResult.isValid shouldBe false
+        scanResult = QRScanResult("https://localhost/?")
+        scanResult.isValid shouldBe false
+        scanResult = QRScanResult("htps://wrongformat.com")
+        scanResult.isValid shouldBe false
+        scanResult =
+            QRScanResult("https://localhost/%20?3D6D08-3567F3F2-4DCF-43A3-8737-4CD1F87D6FDA")
+        scanResult.isValid shouldBe false
+        scanResult =
+            QRScanResult("https://some-host.com/?3D6D08-3567F3F2-4DCF-43A3-8737-4CD1F87D6FDA")
+        scanResult.isValid shouldBe false
+        scanResult = QRScanResult("https://localhost/?3567F3F2-4DCF-43A3-8737-4CD1F87D6FDA")
+        scanResult.isValid shouldBe false
+        scanResult = QRScanResult("https://localhost/?4CD1F87D6FDA")
+        scanResult.isValid shouldBe false
+    }
+
+    @Test
+    fun extractGUID() {
+        QRScanResult("https://localhost/?$guid").guid shouldBe guid
+    }
+}
+
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionConstantsTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionConstantsTest.kt
index 98efa5fec86386ae2035ec6699f6a62b743e42b0..b65d00b6985fe7c66fadaf97c33cb4ee90915817 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionConstantsTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionConstantsTest.kt
@@ -11,13 +11,16 @@ class SubmissionConstantsTest {
         Assert.assertEquals(KeyType.GUID.name, "GUID")
         Assert.assertEquals(KeyType.TELETAN.name, "TELETAN")
 
-        Assert.assertEquals(SubmissionConstants.REGISTRATION_TOKEN_URL, "version/v1/registrationToken")
+        Assert.assertEquals(
+            SubmissionConstants.REGISTRATION_TOKEN_URL,
+            "version/v1/registrationToken"
+        )
         Assert.assertEquals(SubmissionConstants.TEST_RESULT_URL, "version/v1/testresult")
         Assert.assertEquals(SubmissionConstants.TAN_REQUEST_URL, "version/v1/tan")
 
-        Assert.assertEquals(SubmissionConstants.MAX_QR_CODE_LENGTH, 150)
-        Assert.assertEquals(SubmissionConstants.MAX_GUID_LENGTH, 80)
-        Assert.assertEquals(SubmissionConstants.GUID_SEPARATOR, '?')
+        Assert.assertEquals(QRScanResult.MAX_QR_CODE_LENGTH, 150)
+        Assert.assertEquals(QRScanResult.MAX_GUID_LENGTH, 80)
+        Assert.assertEquals(QRScanResult.GUID_SEPARATOR, '?')
 
         Assert.assertEquals(SubmissionConstants.SERVER_ERROR_CODE_400, 400)
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt
index fef63707083f8e07ed413d47824cb7032a7b8835..f1d222553e27a11b1f4dfbab4cbb86add4466170 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/SubmissionServiceTest.kt
@@ -163,26 +163,4 @@ class SubmissionServiceTest {
         }
     }
 
-    @Test
-    fun containsValidGUID() {
-        // valid
-        assertThat(
-            SubmissionService.containsValidGUID("https://bs-sd.de/covid-19/?$guid"),
-            equalTo(true)
-        )
-
-        // invalid
-        assertThat(
-            SubmissionService.containsValidGUID("https://no-guid-here"),
-            equalTo(false)
-        )
-    }
-
-    @Test
-    fun extractGUID() {
-        assertThat(
-            SubmissionService.extractGUID("https://bs-sd.de/covid-19/?$guid"),
-            equalTo(guid)
-        )
-    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModelTest.kt
index a7fa73cbf1963e41a9b698b328dd807e4bda4d97..5a93e5ac213f30f811bfc8e57e5b8ece230c71ae 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModelTest.kt
@@ -51,7 +51,7 @@ class SubmissionViewModelTest {
 
         // valid guid
         val guid = "123456-12345678-1234-4DA7-B166-B86D85475064"
-        viewModel.validateAndStoreTestGUID("https://bs-sd.de/covid-19/?$guid")
+        viewModel.validateAndStoreTestGUID("https://localhost/?$guid")
         viewModel.scanStatus.value?.getContent().let { Assert.assertEquals(ScanStatus.SUCCESS, it) }
 
         // invalid guid