From 11b9a127a21c175c08e3580959dcf971ed1eb048 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Mon, 11 Aug 2025 12:13:53 +0530 Subject: [PATCH 01/52] wip --- .../problem/security/service/SSRFAnalyser.kt | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 1d82c312f9..beb392030c 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -166,8 +166,37 @@ class SSRFAnalyser { * TODO: Need to rename the word manual to something meaningful later */ private fun manualClassifier() { - // TODO: Can use the extracted CSV to map the parameter name - // to the vulnerability class. + // TODO: Can use the extracted CSV to map the parameter name patterns. + individualsInSolution.forEach { evaluatedIndividual -> + evaluatedIndividual.evaluatedMainActions().forEach { a -> + val action = a.action + if (action is RestCallAction) { + val actionFaultMapping = ActionFaultMapping(action.getName()) + val inputFaultMapping: MutableMap = + extractBodyParameters(action.parameters) + + inputFaultMapping.forEach { paramName, paramMapping -> + val answer = if (!paramMapping.description.isNullOrBlank()) { + // TODO: Manual + false + } else { + // TODO: Manual + false + } + + if (answer != null && answer) { + paramMapping.addSecurityFaultCategory(DefinedFaultCategory.SSRF) + actionFaultMapping.addSecurityFaultCategory(DefinedFaultCategory.SSRF) + actionFaultMapping.isVulnerable = true + } + } + + // Assign the param mapping + actionFaultMapping.params = inputFaultMapping + actionVulnerabilityMapping[action.getName()] = actionFaultMapping + } + } + } } @@ -210,7 +239,6 @@ class SSRFAnalyser { // Assign the param mapping actionFaultMapping.params = inputFaultMapping - actionVulnerabilityMapping[action.getName()] = actionFaultMapping } } From 59469ade007785952622d7854e30f6825cfedac5 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 13 Aug 2025 20:54:38 +0530 Subject: [PATCH 02/52] refactor --- .../problem/security/service/SSRFAnalyser.kt | 103 ++++++------------ 1 file changed, 36 insertions(+), 67 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 44897aa86d..e1f91e60fd 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -9,9 +9,6 @@ import org.evomaster.core.problem.api.param.Param import org.evomaster.core.problem.rest.builder.RestIndividualSelectorUtils import org.evomaster.core.problem.rest.data.RestCallAction import org.evomaster.core.problem.rest.data.RestIndividual -import org.evomaster.core.problem.rest.param.BodyParam -import org.evomaster.core.problem.rest.param.HeaderParam -import org.evomaster.core.problem.rest.param.QueryParam import org.evomaster.core.problem.security.data.ActionFaultMapping import org.evomaster.core.problem.security.data.InputFaultMapping import org.evomaster.core.problem.security.SSRFUtil @@ -23,7 +20,6 @@ import org.evomaster.core.search.gene.optional.ChoiceGene import org.evomaster.core.search.gene.optional.CustomMutationRateGene import org.evomaster.core.search.gene.optional.OptionalGene import org.evomaster.core.search.gene.string.StringGene -import org.evomaster.core.search.gene.utils.GeneUtils import org.evomaster.core.search.service.Archive import org.evomaster.core.search.service.FitnessFunction import org.slf4j.Logger @@ -160,23 +156,6 @@ class SSRFAnalyser { // Are we going mark potential vulnerability classes as one time // job or going to evaluate each time (which is costly). - when (config.vulnerableInputClassificationStrategy) { - EMConfig.VulnerableInputClassificationStrategy.MANUAL -> { - manualClassifier() - } - - EMConfig.VulnerableInputClassificationStrategy.LLM -> { - llmClassifier() - } - } - } - - /** - * TODO: Classify based on manual - * TODO: Need to rename the word manual to something meaningful later - */ - private fun manualClassifier() { - // TODO: Can use the extracted CSV to map the parameter name patterns. individualsInSolution.forEach { evaluatedIndividual -> evaluatedIndividual.evaluatedMainActions().forEach { a -> val action = a.action @@ -186,15 +165,17 @@ class SSRFAnalyser { extractBodyParameters(action.parameters) inputFaultMapping.forEach { paramName, paramMapping -> - val answer = if (!paramMapping.description.isNullOrBlank()) { - // TODO: Manual - false - } else { - // TODO: Manual - false + val answer = when (config.vulnerableInputClassificationStrategy) { + EMConfig.VulnerableInputClassificationStrategy.MANUAL -> { + manualClassifier(paramName, paramMapping.description) + } + + EMConfig.VulnerableInputClassificationStrategy.LLM -> { + llmClassifier(paramName, paramMapping.description) + } } - if (answer != null && answer) { + if (answer) { paramMapping.addSecurityFaultCategory(DefinedFaultCategory.SSRF) actionFaultMapping.addSecurityFaultCategory(DefinedFaultCategory.SSRF) actionFaultMapping.isVulnerable = true @@ -207,52 +188,40 @@ class SSRFAnalyser { } } } - } + } /** - * Private method to classify parameters using a large language model. + * A private method to identify parameter is a potentially holds URL value + * using a Regex based approach. */ - private fun llmClassifier() { - // For now, we consider only the individuals selected from [Archive] - // TODO: This can be isolated to classify at the beginning of the search - individualsInSolution.forEach { evaluatedIndividual -> - evaluatedIndividual.evaluatedMainActions().forEach { a -> - val action = a.action - if (action is RestCallAction && !actionVulnerabilityMapping.containsKey(action.getName())) { - val actionFaultMapping = ActionFaultMapping(action.getName()) - val inputFaultMapping: MutableMap = - extractBodyParameters(action.parameters) - - inputFaultMapping.forEach { paramName, paramMapping -> - val answer = if (!paramMapping.description.isNullOrBlank()) { - languageModelConnector.query( - SSRFUtil.Companion.getPromptWithNameAndDescription( - paramMapping.name, - paramMapping.description - ) - ) - } else { - languageModelConnector.query( - SSRFUtil.Companion.getPromptWithNameOnly( - paramMapping.name - ) - ) - } + private fun manualClassifier(name: String, description: String? = null): Boolean { + // TODO: Only regex or wordbag can be used from extracted parameter names. + return false + } - if (answer != null && answer.answer == SSRFUtil.Companion.SSRF_PROMPT_ANSWER_FOR_POSSIBILITY) { - paramMapping.addSecurityFaultCategory(DefinedFaultCategory.SSRF) - actionFaultMapping.addSecurityFaultCategory(DefinedFaultCategory.SSRF) - actionFaultMapping.isVulnerable = true - } - } - // Assign the param mapping - actionFaultMapping.params = inputFaultMapping - actionVulnerabilityMapping[action.getName()] = actionFaultMapping - } - } + /** + * Private method to identify parameter is a potentially holds URL value, + * using a large language model. + */ + private fun llmClassifier(name: String, description: String? = null): Boolean { + val answer = if (!description.isNullOrBlank()) { + languageModelConnector.query( + SSRFUtil.Companion.getPromptWithNameAndDescription( + name, + description + ) + ) + } else { + languageModelConnector.query( + SSRFUtil.Companion.getPromptWithNameOnly( + name + ) + ) } + + return answer != null && answer.answer == SSRFUtil.Companion.SSRF_PROMPT_ANSWER_FOR_POSSIBILITY } /** From a5d492f2d27db40620c9104048ef39db41142a8b Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 13 Aug 2025 21:17:34 +0530 Subject: [PATCH 03/52] wip --- .../service/fitness/AbstractRestFitness.kt | 6 ++--- .../problem/security/service/SSRFAnalyser.kt | 22 +++++++++---------- .../openapi/v3/security/ssrf/SsrfEMTest.kt | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt index 0c09978ba8..4b274f6fcb 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt @@ -80,7 +80,7 @@ abstract class AbstractRestFitness : HttpWsFitness() { protected lateinit var harvestResponseHandler: HarvestActualHttpWsResponseHandler @Inject - protected lateinit var SSRFAnalyser: SSRFAnalyser + protected lateinit var ssrfAnalyser: SSRFAnalyser @Inject protected lateinit var responsePool: DataPool @@ -762,7 +762,7 @@ abstract class AbstractRestFitness : HttpWsFitness() { } if (config.security && config.ssrf) { - if (SSRFAnalyser.hasVulnerableInputs(a)) { + if (ssrfAnalyser.hasVulnerableInputs(a)) { rcr.setVulnerableForSSRF(true) } } @@ -1180,7 +1180,7 @@ abstract class AbstractRestFitness : HttpWsFitness() { individual.seeMainExecutableActions().forEach { val ar = actionResults.find { r -> r.sourceLocalId == it.getLocalId() } as RestCallResult - if (ar != null && ar.getResultValue(HttpWsCallResult.VULNERABLE_SSRF)?.toBoolean() ?: false) { + if (ar.getResultValue(HttpWsCallResult.VULNERABLE_SSRF)?.toBoolean() ?: false) { val scenarioId = idMapper.handleLocalTarget( idMapper.getFaultDescriptiveId(DefinedFaultCategory.SSRF, it.getName()) ) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index e1f91e60fd..87b18bbe22 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -126,20 +126,20 @@ class SSRFAnalyser { should check the content of rcr result */ - if (!actionVulnerabilityMapping.containsKey(action.getName())) { - return false - } +// var hasCallbackURL = false - var hasCallbackURL = false +// action.parameters.forEach { param -> +// val genes = getStringGenesFromParam(param.seeGenes()) +// genes.forEach { gene -> +// hasCallbackURL = httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) +// } +// } - action.parameters.forEach { param -> - val genes = getStringGenesFromParam(param.seeGenes()) - genes.forEach { gene -> - hasCallbackURL = httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) - } - } + val d = action.parameters.any { it.genes.any { gene -> httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) } } + + val x = httpCallbackVerifier.verify(action.getName()) - return hasCallbackURL && httpCallbackVerifier.verify(action.getName()) + return httpCallbackVerifier.verify(action.getName()) } /** diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt index d5716a5e43..bd4ce2c459 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt @@ -18,7 +18,7 @@ class SsrfEMTest : SpringTestBase() { } } - @Disabled("WIP") +// @Disabled("WIP") @Test fun testSsrfEM() { runTestHandlingFlakyAndCompilation( From 3912c9420293c3cd64d7b838ff03c3c7a480e158 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Mon, 18 Aug 2025 14:35:23 +0530 Subject: [PATCH 04/52] clean-up --- .../problem/security/service/SSRFAnalyser.kt | 64 +++++++------------ 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 80200669df..c9d1622964 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -161,46 +161,6 @@ class SSRFAnalyser { // Are we going mark potential vulnerability classes as one time // job or going to evaluate each time (which is costly). - when (config.vulnerableInputClassificationStrategy) { - EMConfig.VulnerableInputClassificationStrategy.MANUAL -> { - manualClassifier() - } - - EMConfig.VulnerableInputClassificationStrategy.LLM -> { - llmClassifier() - } - } - } - - fun getVulnerableParameterName(action: RestCallAction): String? { - if (actionVulnerabilityMapping.containsKey(action.getName())) { - val mapping = actionVulnerabilityMapping[action.getName()] - if (mapping != null) { - val param = mapping.params.filter { it.value.securityFaults.contains( - DefinedFaultCategory.SSRF) } - return param.keys.first() - } - } - - return null - } - - /** - * TODO: Classify based on manual - * TODO: Need to rename the word manual to something meaningful later - */ - private fun manualClassifier() { - // TODO: Can use the extracted CSV to map the parameter name - // to the vulnerability class. - } - - - /** - * Private method to classify parameters using a large language model. - */ - private fun llmClassifier() { - // For now, we consider only the individuals selected from [Archive] - // TODO: This can be isolated to classify at the beginning of the search individualsInSolution.forEach { evaluatedIndividual -> evaluatedIndividual.evaluatedMainActions().forEach { a -> val action = a.action @@ -234,6 +194,28 @@ class SSRFAnalyser { } } +// when (config.vulnerableInputClassificationStrategy) { +// EMConfig.VulnerableInputClassificationStrategy.MANUAL -> { +// manualClassifier() +// } +// +// EMConfig.VulnerableInputClassificationStrategy.LLM -> { +// llmClassifier() +// } +// } + } + + fun getVulnerableParameterName(action: RestCallAction): String? { + if (actionVulnerabilityMapping.containsKey(action.getName())) { + val mapping = actionVulnerabilityMapping[action.getName()] + if (mapping != null) { + val param = mapping.params.filter { it.value.securityFaults.contains( + DefinedFaultCategory.SSRF) } + return param.keys.first() + } + } + + return null } /** @@ -241,7 +223,7 @@ class SSRFAnalyser { * using a Regex based approach. */ private fun manualClassifier(name: String, description: String? = null): Boolean { - // TODO: Only regex or wordbag can be used from extracted parameter names. + // TODO: Only regex or word bag can be used from extracted parameter names. return false } From 94e6e44ffd71877a946afe7632f2cdabfde863a3 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Mon, 18 Aug 2025 14:39:12 +0530 Subject: [PATCH 05/52] minor clean-up --- .../org/evomaster/core/problem/security/service/SSRFAnalyser.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index c9d1622964..5f0a3822ca 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -142,8 +142,6 @@ class SSRFAnalyser { } } - val x = httpCallbackVerifier.verify(action.getName()) - return httpCallbackVerifier.verify(action.getName()) } From eda11782604c79582567476e4ad9813315e72a13 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 19 Aug 2025 12:07:27 +0530 Subject: [PATCH 06/52] disabled e2e --- .../e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt index bd4ce2c459..d5716a5e43 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/SsrfEMTest.kt @@ -18,7 +18,7 @@ class SsrfEMTest : SpringTestBase() { } } -// @Disabled("WIP") + @Disabled("WIP") @Test fun testSsrfEM() { runTestHandlingFlakyAndCompilation( From 4d25212344f54bf5514e9d4c96a02eceb85ace0e Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 19 Aug 2025 12:18:19 +0530 Subject: [PATCH 07/52] replacing GeneUtils new method --- .../problem/security/service/SSRFAnalyser.kt | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index f56fcc19c0..10e278bfb5 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -20,6 +20,7 @@ import org.evomaster.core.search.gene.wrapper.ChoiceGene import org.evomaster.core.search.gene.wrapper.CustomMutationRateGene import org.evomaster.core.search.gene.wrapper.OptionalGene import org.evomaster.core.search.gene.string.StringGene +import org.evomaster.core.search.gene.utils.GeneUtils import org.evomaster.core.search.service.Archive import org.evomaster.core.search.service.FitnessFunction import org.slf4j.Logger @@ -63,6 +64,10 @@ class SSRFAnalyser { */ private lateinit var individualsInSolution: List> + private val urlRegexPattern: Regex = Regex("\\burl\\b") + + private val potentialUrlParamNames: List = listOf("url", "source", "target") + companion object { private val log: Logger = LoggerFactory.getLogger(SSRFAnalyser::class.java) } @@ -70,6 +75,7 @@ class SSRFAnalyser { @PostConstruct fun init() { log.debug("Initializing {}", SSRFAnalyser::class.simpleName) + loadURLParamNamesFromFile() } @PreDestroy @@ -167,7 +173,7 @@ class SSRFAnalyser { val inputFaultMapping: MutableMap = extractBodyParameters(action.parameters) - inputFaultMapping.forEach { paramName, paramMapping -> + inputFaultMapping.forEach { (paramName, paramMapping) -> val answer = when (config.vulnerableInputClassificationStrategy) { EMConfig.VulnerableInputClassificationStrategy.MANUAL -> { manualClassifier(paramName, paramMapping.description) @@ -191,16 +197,6 @@ class SSRFAnalyser { } } } - -// when (config.vulnerableInputClassificationStrategy) { -// EMConfig.VulnerableInputClassificationStrategy.MANUAL -> { -// manualClassifier() -// } -// -// EMConfig.VulnerableInputClassificationStrategy.LLM -> { -// llmClassifier() -// } -// } } fun getVulnerableParameterName(action: RestCallAction): String? { @@ -222,6 +218,23 @@ class SSRFAnalyser { */ private fun manualClassifier(name: String, description: String? = null): Boolean { // TODO: Only regex or word bag can be used from extracted parameter names. + var value = 0.0 + + if (name.lowercase().matches(urlRegexPattern)) { + value += 0.5 + } + if (description != null) { + if (description.lowercase().matches(urlRegexPattern)) { + value += 0.3 + } + } + if (potentialUrlParamNames.contains(name)) { + value += 1.0 + } + if (value > 0.5) { + return true + } + return false } @@ -257,15 +270,13 @@ class SSRFAnalyser { ): MutableMap { val output = mutableMapOf() - parameters.forEach { param -> - val genes = getStringGenesFromParam(param.seeGenes()) + val genes = GeneUtils.getAllStringFields(parameters) - genes.forEach { gene -> - output[gene.name] = InputFaultMapping( - gene.name, - gene.description, - ) - } + genes.forEach { gene -> + output[gene.name] = InputFaultMapping( + gene.name, + gene.description, + ) } return output @@ -387,4 +398,8 @@ class SSRFAnalyser { return output } + + private fun loadURLParamNamesFromFile() { + // TODO + } } From 2548e6c48242aa983c254e6e44a6ecb9a33e7c4f Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 19 Aug 2025 12:19:40 +0530 Subject: [PATCH 08/52] minor change --- .../core/problem/security/service/SSRFAnalyser.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 10e278bfb5..82ccd666e2 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -141,14 +141,13 @@ class SSRFAnalyser { should check the content of rcr result */ - val hasCallbackURL = action.parameters.any { param -> - val genes = getStringGenesFromParam(param.seeGenes()) - genes.any { gene -> - httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) - } + val genes = GeneUtils.getAllStringFields(action.parameters) + + val hasCallBackURL = genes.any { gene -> + httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) } - return httpCallbackVerifier.verify(action.getName()) + return httpCallbackVerifier.verify(action.getName()) && hasCallBackURL } /** From 6ac1233034a6afd97e36252d52134584a0620083 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 19 Aug 2025 12:20:12 +0530 Subject: [PATCH 09/52] clean-up --- .../problem/security/service/SSRFAnalyser.kt | 46 ++----------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 82ccd666e2..32c6c359fe 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -15,11 +15,6 @@ import org.evomaster.core.problem.security.SSRFUtil import org.evomaster.core.search.EvaluatedIndividual import org.evomaster.core.search.Solution import org.evomaster.core.search.gene.Gene -import org.evomaster.core.search.gene.ObjectGene -import org.evomaster.core.search.gene.wrapper.ChoiceGene -import org.evomaster.core.search.gene.wrapper.CustomMutationRateGene -import org.evomaster.core.search.gene.wrapper.OptionalGene -import org.evomaster.core.search.gene.string.StringGene import org.evomaster.core.search.gene.utils.GeneUtils import org.evomaster.core.search.service.Archive import org.evomaster.core.search.service.FitnessFunction @@ -202,8 +197,11 @@ class SSRFAnalyser { if (actionVulnerabilityMapping.containsKey(action.getName())) { val mapping = actionVulnerabilityMapping[action.getName()] if (mapping != null) { - val param = mapping.params.filter { it.value.securityFaults.contains( - DefinedFaultCategory.SSRF) } + val param = mapping.params.filter { + it.value.securityFaults.contains( + DefinedFaultCategory.SSRF + ) + } return param.keys.first() } } @@ -364,40 +362,6 @@ class SSRFAnalyser { } } - private fun getStringGenesFromParam(genes: List): List { - val output = mutableListOf() - - genes.forEach { gene -> - when (gene) { - is StringGene -> { - output.add(gene) - } - - is OptionalGene -> { - output.addAll(getStringGenesFromParam(gene.getViewOfChildren())) - } - - is ObjectGene -> { - output.addAll(getStringGenesFromParam(gene.getViewOfChildren())) - } - - is ChoiceGene<*> -> { - output.addAll(getStringGenesFromParam(gene.getViewOfChildren())) - } - - is CustomMutationRateGene<*> -> { - output.addAll(getStringGenesFromParam(gene.getViewOfChildren())) - } - - else -> { - // Do nothing - } - } - } - - return output - } - private fun loadURLParamNamesFromFile() { // TODO } From 6e616e15300b795244d7924544721eaa0ad3c2b0 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:30:18 +0530 Subject: [PATCH 10/52] minor cleanup --- .../problem/security/service/SSRFAnalyser.kt | 16 +++++----------- .../v3/security/ssrf/base/SSRFBaseEMTest.kt | 6 +++--- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 32c6c359fe..8ffecc1bca 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -214,24 +214,18 @@ class SSRFAnalyser { * using a Regex based approach. */ private fun manualClassifier(name: String, description: String? = null): Boolean { - // TODO: Only regex or word bag can be used from extracted parameter names. - var value = 0.0 + if (potentialUrlParamNames.contains(name)) { + return true + } if (name.lowercase().matches(urlRegexPattern)) { - value += 0.5 + return true } if (description != null) { if (description.lowercase().matches(urlRegexPattern)) { - value += 0.3 + return true } } - if (potentialUrlParamNames.contains(name)) { - value += 1.0 - } - if (value > 0.5) { - return true - } - return false } diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt index 0ea20152fc..b0904eb126 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt @@ -18,7 +18,7 @@ class SSRFBaseEMTest : SpringTestBase() { } } - @Disabled("WIP") +// @Disabled("WIP") @Test fun testSSRFEM() { runTestHandlingFlakyAndCompilation( @@ -32,9 +32,9 @@ class SSRFBaseEMTest : SpringTestBase() { setOption(args, "security", "true") setOption(args, "ssrf", "true") - setOption(args, "vulnerableInputClassificationStrategy", "LLM") + setOption(args, "vulnerableInputClassificationStrategy", "MANUAL") - setOption(args, "languageModelConnector", "true") + setOption(args, "languageModelConnector", "false") setOption(args, "schemaOracles", "false") val solution = initAndRun(args) From e43daf90b6e467e194d4874ba8f47039d61943dc Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:50:01 +0530 Subject: [PATCH 11/52] comments --- .../core/problem/rest/service/fitness/AbstractRestFitness.kt | 1 + .../evomaster/core/problem/security/service/SSRFAnalyser.kt | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt index ef4d16142b..aa59ba2d69 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt @@ -737,6 +737,7 @@ abstract class AbstractRestFitness : HttpWsFitness() { // ResourceRestFitness get invoked during the recompute if (config.security && config.ssrf) { if (ssrfAnalyser.anyCallsMadeToHTTPVerifier(a)) { + // Code reach this point during the search, which is unnecessary during search rcr.setVulnerableForSSRF(true) } } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 8ffecc1bca..ef513d763e 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -142,6 +142,7 @@ class SSRFAnalyser { httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) } + // To Andrea: Code reach this point during the search return httpCallbackVerifier.verify(action.getName()) && hasCallBackURL } @@ -237,14 +238,14 @@ class SSRFAnalyser { private fun llmClassifier(name: String, description: String? = null): Boolean { val answer = if (!description.isNullOrBlank()) { languageModelConnector.query( - SSRFUtil.Companion.getPromptWithNameAndDescription( + SSRFUtil.getPromptWithNameAndDescription( name, description ) ) } else { languageModelConnector.query( - SSRFUtil.Companion.getPromptWithNameOnly( + SSRFUtil.getPromptWithNameOnly( name ) ) From c2ab99a5e97cf7e596f691289e65ff1d08d97f89 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:10:18 +0530 Subject: [PATCH 12/52] minor changes --- .../problem/security/service/SSRFAnalyser.kt | 4 ++-- .../security/ssrf/base/SSRFBaseApplication.kt | 12 ++++------ .../v3/security/ssrf/base/SSRFBaseEMTest.kt | 23 +++++++++++-------- .../security/ssrf/header/SSRFHeaderEMTest.kt | 6 +++-- .../v3/security/ssrf/query/SSRFQueryEMTest.kt | 6 +++-- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index ef513d763e..3127b35b6b 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -90,7 +90,7 @@ class SSRFAnalyser { individualsInSolution = RestIndividualSelectorUtils.findIndividuals( individuals, - statusCodes = listOf(200, 201) + statusCodes = listOf(200, 201, 204) ) if (individualsInSolution.isEmpty()) { @@ -119,7 +119,7 @@ class SSRFAnalyser { // TODO: This is for development, remove it later val individualsAfterExecution = RestIndividualSelectorUtils.findIndividuals( this.archive.extractSolution().individuals, - statusCodes = listOf(200, 201) + statusCodes = listOf(200, 201, 204) ) log.debug("Total individuals after vulnerability analysis: {}", individualsAfterExecution.size) diff --git a/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt b/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt index 7671760399..0043eb0cbf 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt @@ -42,16 +42,15 @@ open class SSRFBaseApplication { ) @PostMapping(path = ["/fetch/image"]) open fun fetchUserImage(@RequestBody userInfo: UserDto): ResponseEntity { - if (userInfo.userId!!.isNotEmpty() && userInfo.profileImageUrl!!.isNotEmpty()) { + if (userInfo.profileImageUrl!!.isNotEmpty()) { return try { val url = URL(userInfo.profileImageUrl) val connection = url.openConnection() as HttpURLConnection - connection.requestMethod = "GET" - connection.connectTimeout = 1000 + connection.setRequestProperty("accept", "application/json") // Note: Here the saving file should exist if (connection.responseCode == 200) { - return ResponseEntity.status(200).build() + return ResponseEntity.status(200).body("OK") } ResponseEntity.status(204).body("Unable to fetch remote image.") @@ -81,11 +80,10 @@ open class SSRFBaseApplication { return try { val url = URL(remoteData.sensorUrl) val connection = url.openConnection() as HttpURLConnection - connection.requestMethod = "GET" - connection.connectTimeout = 1000 + connection.setRequestProperty("accept", "application/json") if (connection.responseCode == 200) { - return ResponseEntity.status(200).build() + return ResponseEntity.status(200).body("OK") } ResponseEntity.status(204).body("Unable to fetch sensor data.") diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt index b0904eb126..0ef934e48a 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt @@ -1,9 +1,11 @@ package org.evomaster.e2etests.spring.openapi.v3.security.ssrf.base import com.foo.rest.examples.spring.openapi.v3.security.ssrf.base.SSRFBaseController +import org.evomaster.core.EMConfig import org.evomaster.core.problem.rest.data.HttpVerb import org.evomaster.e2etests.spring.openapi.v3.SpringTestBase import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -14,21 +16,22 @@ class SSRFBaseEMTest : SpringTestBase() { @BeforeAll @JvmStatic fun init() { - initClass(SSRFBaseController()) + val config = EMConfig() + config.instrumentMR_NET = true + initClass(SSRFBaseController(), config) } } -// @Disabled("WIP") + // @Disabled("WIP") @Test fun testSSRFEM() { runTestHandlingFlakyAndCompilation( "SSRFBaseEMTest", - 300, + 200, ) { args: MutableList -> setOption(args, "externalServiceIPSelectionStrategy", "USER") - setOption(args, "externalServiceIP", "127.0.0.4") - setOption(args, "instrumentMR_NET", "true") + setOption(args, "externalServiceIP", "127.0.0.50") setOption(args, "security", "true") setOption(args, "ssrf", "true") @@ -39,13 +42,13 @@ class SSRFBaseEMTest : SpringTestBase() { val solution = initAndRun(args) - Assertions.assertTrue(solution.individuals.isNotEmpty()) + assertTrue(solution.individuals.isNotEmpty()) - assertHasAtLeastOne(solution, HttpVerb.POST, 201, "/api/fetch/data", null) - assertHasAtLeastOne(solution, HttpVerb.POST, 201, "/api/fetch/image", null) + assertHasAtLeastOne(solution, HttpVerb.POST, 200, "/api/fetch/data", "OK") + assertHasAtLeastOne(solution, HttpVerb.POST, 200, "/api/fetch/image", "OK") - assertHasAtLeastOne(solution, HttpVerb.POST, 200, "/api/fetch/data", "Unable to fetch sensor data.") - assertHasAtLeastOne(solution, HttpVerb.POST, 200, "/api/fetch/image", "Unable to fetch remote image.") + assertHasAtLeastOne(solution, HttpVerb.POST, 204, "/api/fetch/data", "Unable to fetch sensor data.") + assertHasAtLeastOne(solution, HttpVerb.POST, 204, "/api/fetch/image", "Unable to fetch remote image.") } } } diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt index 1699506ab9..849516c296 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt @@ -1,6 +1,7 @@ package org.evomaster.e2etests.spring.openapi.v3.security.ssrf.header import com.foo.rest.examples.spring.openapi.v3.security.ssrf.header.SSRFHeaderController +import org.evomaster.core.EMConfig import org.evomaster.core.problem.rest.data.HttpVerb import org.evomaster.e2etests.spring.openapi.v3.SpringTestBase import org.junit.jupiter.api.Assertions @@ -14,7 +15,9 @@ class SSRFHeaderEMTest: SpringTestBase() { @BeforeAll @JvmStatic fun init() { - initClass(SSRFHeaderController()) + val config = EMConfig() + config.instrumentMR_NET = true + initClass(SSRFHeaderController(), config) } } @@ -28,7 +31,6 @@ class SSRFHeaderEMTest: SpringTestBase() { setOption(args, "externalServiceIPSelectionStrategy", "USER") setOption(args, "externalServiceIP", "127.0.0.6") - setOption(args, "instrumentMR_NET", "true") setOption(args, "security", "true") setOption(args, "ssrf", "true") diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 00f1391508..a2353d24c2 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -1,6 +1,7 @@ package org.evomaster.e2etests.spring.openapi.v3.security.ssrf.query import com.foo.rest.examples.spring.openapi.v3.security.ssrf.query.SSRFQueryController +import org.evomaster.core.EMConfig import org.evomaster.core.problem.rest.data.HttpVerb import org.evomaster.e2etests.spring.openapi.v3.SpringTestBase import org.junit.jupiter.api.Assertions @@ -14,7 +15,9 @@ class SSRFQueryEMTest: SpringTestBase() { @BeforeAll @JvmStatic fun init() { - initClass(SSRFQueryController()) + val config = EMConfig() + config.instrumentMR_NET = true + initClass(SSRFQueryController(), config) } } @@ -28,7 +31,6 @@ class SSRFQueryEMTest: SpringTestBase() { setOption(args, "externalServiceIPSelectionStrategy", "USER") setOption(args, "externalServiceIP", "127.0.0.8") - setOption(args, "instrumentMR_NET", "true") setOption(args, "security", "true") setOption(args, "ssrf", "true") From feaed322af6feb6fe764aaaa0a297fcc305c038a Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:12:56 +0530 Subject: [PATCH 13/52] clean-ups --- .../openapi/v3/security/ssrf/base/SSRFBaseApplication.kt | 4 ++-- .../openapi/v3/security/ssrf/query/SSRFQueryApplication.kt | 2 +- .../spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt | 6 ++++-- .../openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt | 4 ++-- .../openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 4 ++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt b/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt index 0043eb0cbf..ef6cb6772a 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt @@ -55,7 +55,7 @@ open class SSRFBaseApplication { ResponseEntity.status(204).body("Unable to fetch remote image.") } catch (e: Exception) { - ResponseEntity.internalServerError().body(e.message) + ResponseEntity.status(204).body("Unable to fetch remote image.") } } @@ -88,7 +88,7 @@ open class SSRFBaseApplication { ResponseEntity.status(204).body("Unable to fetch sensor data.") } catch (e: Exception) { - ResponseEntity.internalServerError().body(e.message) + ResponseEntity.status(204).body("Unable to fetch remote image.") } } diff --git a/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/query/SSRFQueryApplication.kt b/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/query/SSRFQueryApplication.kt index e03c7ebeb8..6f18dc8838 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/query/SSRFQueryApplication.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/query/SSRFQueryApplication.kt @@ -52,7 +52,7 @@ open class SSRFQueryApplication { } ResponseEntity.status(204).build() } catch (e: Exception) { - ResponseEntity.internalServerError().body(e.message) + ResponseEntity.status(204).body("Unable to fetch remote image.") } } diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt index 0ef934e48a..e004fd8b12 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt @@ -17,7 +17,7 @@ class SSRFBaseEMTest : SpringTestBase() { @JvmStatic fun init() { val config = EMConfig() - config.instrumentMR_NET = true + config.instrumentMR_NET = false initClass(SSRFBaseController(), config) } } @@ -30,7 +30,9 @@ class SSRFBaseEMTest : SpringTestBase() { 200, ) { args: MutableList -> - setOption(args, "externalServiceIPSelectionStrategy", "USER") + // This will start spin new instances of mock services each time when a new URL is + // passed. + setOption(args, "externalServiceIPSelectionStrategy", "NONE") setOption(args, "externalServiceIP", "127.0.0.50") setOption(args, "security", "true") diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt index 849516c296..05e321556d 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt @@ -16,7 +16,7 @@ class SSRFHeaderEMTest: SpringTestBase() { @JvmStatic fun init() { val config = EMConfig() - config.instrumentMR_NET = true + config.instrumentMR_NET = false initClass(SSRFHeaderController(), config) } } @@ -29,7 +29,7 @@ class SSRFHeaderEMTest: SpringTestBase() { 300, ) { args: MutableList -> - setOption(args, "externalServiceIPSelectionStrategy", "USER") + setOption(args, "externalServiceIPSelectionStrategy", "NONE") setOption(args, "externalServiceIP", "127.0.0.6") setOption(args, "security", "true") diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index a2353d24c2..7ddd336083 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -16,7 +16,7 @@ class SSRFQueryEMTest: SpringTestBase() { @JvmStatic fun init() { val config = EMConfig() - config.instrumentMR_NET = true + config.instrumentMR_NET = false initClass(SSRFQueryController(), config) } } @@ -29,7 +29,7 @@ class SSRFQueryEMTest: SpringTestBase() { 300, ) { args: MutableList -> - setOption(args, "externalServiceIPSelectionStrategy", "USER") + setOption(args, "externalServiceIPSelectionStrategy", "NONE") setOption(args, "externalServiceIP", "127.0.0.8") setOption(args, "security", "true") From cf17bd3458a9908e85f17e5c0e882e63e91ec2fc Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:32:30 +0530 Subject: [PATCH 14/52] trying to fix --- .../evomaster/core/problem/security/service/SSRFAnalyser.kt | 4 +++- .../spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt | 2 +- .../openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt | 2 +- .../spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 3127b35b6b..4f751ca596 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -61,7 +61,7 @@ class SSRFAnalyser { private val urlRegexPattern: Regex = Regex("\\burl\\b") - private val potentialUrlParamNames: List = listOf("url", "source", "target") + private val potentialUrlParamNames: List = listOf("url", "source", "target", "dataSource") companion object { private val log: Logger = LoggerFactory.getLogger(SSRFAnalyser::class.java) @@ -352,6 +352,8 @@ class SSRFAnalyser { // Only change the param marked for SSRF // This updates the children also recursively gene.setFromStringValue(callBackUrl) + // TODO: to Andrea: Fails with message, + // java.lang.IllegalStateException: setValueBasedOn() is not implemented for gene UrlHttpGene } } } diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt index e004fd8b12..3153c0a408 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt @@ -22,7 +22,7 @@ class SSRFBaseEMTest : SpringTestBase() { } } - // @Disabled("WIP") + @Disabled("WIP") @Test fun testSSRFEM() { runTestHandlingFlakyAndCompilation( diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt index 05e321556d..dd5293d840 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt @@ -26,7 +26,7 @@ class SSRFHeaderEMTest: SpringTestBase() { fun testSSRFHeader() { runTestHandlingFlakyAndCompilation( "SSRFEMTest", - 300, + 100, ) { args: MutableList -> setOption(args, "externalServiceIPSelectionStrategy", "NONE") diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 7ddd336083..3f88bf07e6 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -26,7 +26,7 @@ class SSRFQueryEMTest: SpringTestBase() { fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( "SSRFQueryEMTest", - 300, + 100, ) { args: MutableList -> setOption(args, "externalServiceIPSelectionStrategy", "NONE") From 15d9f59be113f6fa9d7e4c2b50bc2547e12114df Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:47:28 +0530 Subject: [PATCH 15/52] regex fix --- .../evomaster/core/problem/security/service/SSRFAnalyser.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 4f751ca596..ed287b55bb 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -59,7 +59,7 @@ class SSRFAnalyser { */ private lateinit var individualsInSolution: List> - private val urlRegexPattern: Regex = Regex("\\burl\\b") + private val urlRegexPattern: Regex = Regex("/url/ig") private val potentialUrlParamNames: List = listOf("url", "source", "target", "dataSource") @@ -219,11 +219,11 @@ class SSRFAnalyser { return true } - if (name.lowercase().matches(urlRegexPattern)) { + if (name.matches(urlRegexPattern)) { return true } if (description != null) { - if (description.lowercase().matches(urlRegexPattern)) { + if (description.matches(urlRegexPattern)) { return true } } From d21448daa4a4dc0be96d4af005677cd2627c41ab Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:51:50 +0530 Subject: [PATCH 16/52] updated regex --- .../evomaster/core/problem/security/service/SSRFAnalyser.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index ed287b55bb..9d08ada493 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -59,9 +59,9 @@ class SSRFAnalyser { */ private lateinit var individualsInSolution: List> - private val urlRegexPattern: Regex = Regex("/url/ig") + private val urlRegexPattern: Regex = Regex("/url|source|remote|target/ig") - private val potentialUrlParamNames: List = listOf("url", "source", "target", "dataSource") + private val potentialUrlParamNames: List = listOf("url", "source", "target", "datasource") companion object { private val log: Logger = LoggerFactory.getLogger(SSRFAnalyser::class.java) @@ -215,7 +215,7 @@ class SSRFAnalyser { * using a Regex based approach. */ private fun manualClassifier(name: String, description: String? = null): Boolean { - if (potentialUrlParamNames.contains(name)) { + if (potentialUrlParamNames.contains(name.lowercase())) { return true } From d4ae9958226ff293cada0abbd9b5e3fe43a1940b Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:42:40 +0530 Subject: [PATCH 17/52] UrlHttpGene setValueBasedOn --- .../core/search/gene/uri/UrlHttpGene.kt | 16 +++++++++++++++- .../v3/security/ssrf/base/SSRFBaseApplication.kt | 2 ++ .../v3/security/ssrf/base/SSRFBaseEMTest.kt | 2 +- .../v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt index 9b3ce76334..997231df5a 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt @@ -103,6 +103,20 @@ class UrlHttpGene( return false } + override fun setValueBasedOn(value: String): Boolean { + try { + val url = URL(value) + scheme.setFromStringValue(url.protocol) + host.setFromStringValue(url.host) + port.setFromStringValue(url.port.toString()) + path.setFromStringValue(url.path) + return true + } catch (e: java.lang.Exception) { + return false + } + return false + } + override fun customShouldApplyShallowMutation( randomness: Randomness, selectionStrategy: SubsetGeneMutationSelectionStrategy, @@ -112,4 +126,4 @@ class UrlHttpGene( return false } -} \ No newline at end of file +} diff --git a/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt b/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt index ef6cb6772a..d402de5dd8 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/main/kotlin/com/foo/rest/examples/spring/openapi/v3/security/ssrf/base/SSRFBaseApplication.kt @@ -47,6 +47,7 @@ open class SSRFBaseApplication { val url = URL(userInfo.profileImageUrl) val connection = url.openConnection() as HttpURLConnection connection.setRequestProperty("accept", "application/json") + connection.connectTimeout = 1000 // Note: Here the saving file should exist if (connection.responseCode == 200) { @@ -81,6 +82,7 @@ open class SSRFBaseApplication { val url = URL(remoteData.sensorUrl) val connection = url.openConnection() as HttpURLConnection connection.setRequestProperty("accept", "application/json") + connection.connectTimeout = 1000 if (connection.responseCode == 200) { return ResponseEntity.status(200).body("OK") diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt index 3153c0a408..d13f93a9f6 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt @@ -22,7 +22,7 @@ class SSRFBaseEMTest : SpringTestBase() { } } - @Disabled("WIP") +// @Disabled("WIP") @Test fun testSSRFEM() { runTestHandlingFlakyAndCompilation( diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 3f88bf07e6..f43216b959 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } - @Disabled +// @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( From 4fa1214965ebe8e1d3087c4c370eb35017aa0137 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:48:34 +0530 Subject: [PATCH 18/52] InetGene --- .../org/evomaster/core/search/gene/network/InetGene.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/network/InetGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/network/InetGene.kt index 5b16dea620..c961960f2e 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/network/InetGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/network/InetGene.kt @@ -11,6 +11,7 @@ import org.evomaster.core.search.service.mutator.genemutation.AdditionalGeneMuta import org.evomaster.core.search.service.mutator.genemutation.SubsetGeneMutationSelectionStrategy import org.slf4j.Logger import org.slf4j.LoggerFactory +import java.net.InetAddress class InetGene( name: String, @@ -63,6 +64,11 @@ class InetGene( } } + override fun setValueBasedOn(value: String): Boolean { + // TODO + return false + } + override fun copyValueFrom(other: Gene): Boolean { if (other !is InetGene) { throw IllegalArgumentException("Invalid gene type ${other.javaClass}") @@ -108,4 +114,4 @@ class InetGene( return false } -} \ No newline at end of file +} From fa0fe3030b6f0d65eb6472ebd3a83e943bca3f58 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:49:03 +0530 Subject: [PATCH 19/52] disabled e2e --- .../spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt | 2 +- .../spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt index d13f93a9f6..5498f98592 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt @@ -22,7 +22,7 @@ class SSRFBaseEMTest : SpringTestBase() { } } -// @Disabled("WIP") + @Disabled @Test fun testSSRFEM() { runTestHandlingFlakyAndCompilation( diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index f43216b959..3f88bf07e6 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } -// @Disabled + @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( From 529cde9e709c616db11ba3cf3dbb9d692e853c2b Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:23:44 +0530 Subject: [PATCH 20/52] UrlHttpGene without path --- .../org/evomaster/core/search/gene/collection/ArrayGene.kt | 5 ----- .../kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/collection/ArrayGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/collection/ArrayGene.kt index 4e42a233c4..2565faf932 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/collection/ArrayGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/collection/ArrayGene.kt @@ -295,11 +295,6 @@ class ArrayGene( return false } - override fun setValueBasedOn(value: String): Boolean { - - return false - } - /** * remove an existing element [element] from [elements] */ diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt index 4699daa464..f3a81fd78d 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt @@ -109,7 +109,7 @@ class UrlHttpGene( scheme.setValueBasedOn(url.protocol) host.setValueBasedOn(url.host) port.setValueBasedOn(url.port.toString()) - path.setValueBasedOn(url.path) + // TODO: handle path true } catch (e: java.lang.Exception) { false From 59b20a4e647596f6b0207c6da69dad6259538402 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:30:09 +0530 Subject: [PATCH 21/52] minor change --- .../kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt index f3a81fd78d..93d2531847 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt @@ -110,6 +110,7 @@ class UrlHttpGene( host.setValueBasedOn(url.host) port.setValueBasedOn(url.port.toString()) // TODO: handle path + path.setFromStringValue(url.path) true } catch (e: java.lang.Exception) { false From bce1aae6b5297ac880de1a3664398664ff78c11f Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:46:18 +0530 Subject: [PATCH 22/52] minor change --- .../kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt index d5e0f3b9ec..c1dfa7d6f0 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt @@ -110,7 +110,7 @@ class UrlHttpGene( host.setValueBasedOn(url.host) port.setValueBasedOn(url.port.toString()) // This to make the String similar to what is expected in ArrayGene - val pathValues = url.path.replace("/", ", ") + val pathValues = url.path.drop(1).replace("/", ", ") path.setValueBasedOn(pathValues) // TODO: handle path path.setFromStringValue(url.path) From 217ad3025b2276b5b398f204a20d42aff0b7f2b1 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 27 Aug 2025 21:55:15 +0530 Subject: [PATCH 23/52] working setValueBasedOn for ArrayGene --- .../core/search/gene/collection/ArrayGene.kt | 38 ++++++++++++++++++- .../core/search/gene/uri/UrlHttpGene.kt | 4 +- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/collection/ArrayGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/collection/ArrayGene.kt index f761c5ffd1..ef74698a7c 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/collection/ArrayGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/collection/ArrayGene.kt @@ -10,6 +10,7 @@ import org.evomaster.core.search.gene.interfaces.TaintableGene import org.evomaster.core.search.gene.placeholder.CycleObjectGene import org.evomaster.core.search.gene.placeholder.LimitObjectGene import org.evomaster.core.search.gene.root.CompositeGene +import org.evomaster.core.search.gene.string.StringGene import org.evomaster.core.search.gene.utils.GeneUtils import org.evomaster.core.search.impact.impactinfocollection.ImpactUtils import org.evomaster.core.search.service.AdaptiveParameterControl @@ -295,10 +296,45 @@ class ArrayGene( return false } + @Deprecated("Do not call directly outside this package. Call setFromStringValue") + /** + * To set the children from a String. + * Use comma (,) separated values as String. + */ override fun setValueBasedOn(value: String): Boolean { - val elements = value.split(separatorTag) + val elements = value.split(",") if (elements.isNotEmpty()) { killAllChildren() + when(template) { + is StringGene -> { + val es = mutableListOf() + elements.forEach { + es.add( + StringGene( + name, + it + ).apply { + doInitialize(getSearchGlobalState()?.randomness) + }) + } + addChildren(es) + } + is BooleanGene -> { + val es = mutableListOf() + elements.forEach { + es.add(BooleanGene(name, it.toBoolean()).apply { + doInitialize(getSearchGlobalState()?.randomness) + }) + } + addChildren(es) + } + else -> { + // TODO: Do nothing for now, handle other types + } + } + + return true + // TODO } return false diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt index c1dfa7d6f0..295c1505eb 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/uri/UrlHttpGene.kt @@ -110,10 +110,8 @@ class UrlHttpGene( host.setValueBasedOn(url.host) port.setValueBasedOn(url.port.toString()) // This to make the String similar to what is expected in ArrayGene - val pathValues = url.path.drop(1).replace("/", ", ") + val pathValues = url.path.drop(1).replace("/", ",") path.setValueBasedOn(pathValues) - // TODO: handle path - path.setFromStringValue(url.path) true } catch (e: java.lang.Exception) { false From 25d268d9b10ce14144033cd5c5d8856a1c3a445f Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:44:31 +0530 Subject: [PATCH 24/52] fixes --- .../security/service/HttpCallbackVerifier.kt | 15 ++++++++------- .../core/problem/security/service/SSRFAnalyser.kt | 15 ++++++++------- .../v3/security/ssrf/query/SSRFQueryEMTest.kt | 6 +++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index 789dff2378..2eb59a8152 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -53,7 +53,7 @@ class HttpCallbackVerifier { wireMockServer = WireMockServer(config) wireMockServer!!.start() - wireMockServer!!.stubFor(getDefaultStub()) +// wireMockServer!!.stubFor(getDefaultStub()) } catch (e: Exception) { throw RuntimeException( e.message + @@ -63,19 +63,21 @@ class HttpCallbackVerifier { } fun isCallbackURL(value: String): Boolean { - // Regex pattern looks for URL contains [HTTP_CALLBACK_VERIFIER] address and [HTTPCallbackVerifier] - // port, along with the path /sink/ and UUID as token generated to make the callback URL unique. + // Regex pattern looks for URL contains the pattern generated by the [HTTPCallbackVerifier]. val pattern = - """^http:\/\/localhost:${config.httpCallbackVerifierPort}\/sink\/.{36}""".toRegex() + """^http:\/\/localhost:${config.httpCallbackVerifierPort}\/EM_\d+$""".toRegex() - return pattern.matches(value) + val x = pattern.matches(value) + return x } /** * Method generates a unique callback link to be used as payload for SSRF. */ fun generateCallbackLink(name: String): String { - val ssrfPath = "/sink/${counter++}" + // FIXME: sink/EM_0 <- slash get replaced with a comma at some point, which fails + // the verification based on the metadata + val ssrfPath = "/EM_${counter++}" wireMockServer!!.stubFor( WireMock.any(WireMock.urlEqualTo(ssrfPath)) @@ -86,7 +88,6 @@ class HttpCallbackVerifier { .withStatus(200) .withBody("OK") ) - ) val link = "http://localhost:${wireMockServer!!.port()}$ssrfPath" diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 9d08ada493..7e432829c8 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -136,14 +136,17 @@ class SSRFAnalyser { should check the content of rcr result */ - val genes = GeneUtils.getAllStringFields(action.parameters) - - val hasCallBackURL = genes.any { gene -> + val hasCallBackURL = GeneUtils + .getAllStringFields(action.parameters) + .any { gene -> httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) } - // To Andrea: Code reach this point during the search - return httpCallbackVerifier.verify(action.getName()) && hasCallBackURL + if (hasCallBackURL) { + return httpCallbackVerifier.verify(action.getName()) + } + + return false } /** @@ -352,8 +355,6 @@ class SSRFAnalyser { // Only change the param marked for SSRF // This updates the children also recursively gene.setFromStringValue(callBackUrl) - // TODO: to Andrea: Fails with message, - // java.lang.IllegalStateException: setValueBasedOn() is not implemented for gene UrlHttpGene } } } diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 9cafecda57..16a393b210 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,12 +21,12 @@ class SSRFQueryEMTest: SpringTestBase() { } } - @Disabled +// @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( "SSRFQueryEMTest", - 100, + 80, ) { args: MutableList -> // If mocking enabled, it'll spin new services each time when there is a valid URL. @@ -41,7 +41,7 @@ class SSRFQueryEMTest: SpringTestBase() { Assertions.assertTrue(solution.individuals.isNotEmpty()) - assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/query", "OK") +// assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/query", "OK") } } } From 6179a3bc6decaf5c2b923189ba3f2cb7f21ada99 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:50:39 +0530 Subject: [PATCH 25/52] comments --- .../core/problem/rest/service/fitness/AbstractRestFitness.kt | 4 ++-- .../core/problem/security/service/HttpCallbackVerifier.kt | 3 +-- .../evomaster/core/problem/security/service/SSRFAnalyser.kt | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt index aa59ba2d69..7a92d38048 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt @@ -733,8 +733,8 @@ abstract class AbstractRestFitness : HttpWsFitness() { } // FIXME: Code never reach this when we recompute the fitness under SSRFAnalyser - // So the faults never get marked. - // ResourceRestFitness get invoked during the recompute + // When the execution reach this during recomputing fitness, [HttpCallbackVerifier] + // seems to be [null]. Due to that the method will never return true if any calls made. if (config.security && config.ssrf) { if (ssrfAnalyser.anyCallsMadeToHTTPVerifier(a)) { // Code reach this point during the search, which is unnecessary during search diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index 2eb59a8152..1c034c35ad 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -67,8 +67,7 @@ class HttpCallbackVerifier { val pattern = """^http:\/\/localhost:${config.httpCallbackVerifierPort}\/EM_\d+$""".toRegex() - val x = pattern.matches(value) - return x + return pattern.matches(value) } /** diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 7e432829c8..43fca39782 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -143,7 +143,8 @@ class SSRFAnalyser { } if (hasCallBackURL) { - return httpCallbackVerifier.verify(action.getName()) + val s = httpCallbackVerifier.verify(action.getName()) + return s } return false From e89f72642b85472662f220ed5136790f3b755651 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:53:50 +0530 Subject: [PATCH 26/52] clean-up --- .../core/problem/security/service/HttpCallbackVerifier.kt | 3 +-- .../evomaster/core/problem/security/service/SSRFAnalyser.kt | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index 1c034c35ad..a1c0fad073 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -53,7 +53,7 @@ class HttpCallbackVerifier { wireMockServer = WireMockServer(config) wireMockServer!!.start() -// wireMockServer!!.stubFor(getDefaultStub()) + wireMockServer!!.stubFor(getDefaultStub()) } catch (e: Exception) { throw RuntimeException( e.message + @@ -98,7 +98,6 @@ class HttpCallbackVerifier { /** * @param name represents the Action name - * * During stub creation, stubs are tagged with Action name in the metadata. */ fun verify(name: String): Boolean { diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 43fca39782..7e432829c8 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -143,8 +143,7 @@ class SSRFAnalyser { } if (hasCallBackURL) { - val s = httpCallbackVerifier.verify(action.getName()) - return s + return httpCallbackVerifier.verify(action.getName()) } return false From 17f4356c26b1d585708352dbbc4db38ddcd06b16 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:54:25 +0530 Subject: [PATCH 27/52] updated url pattern --- .../core/problem/security/service/HttpCallbackVerifier.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index a1c0fad073..2f92b11202 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -65,7 +65,7 @@ class HttpCallbackVerifier { fun isCallbackURL(value: String): Boolean { // Regex pattern looks for URL contains the pattern generated by the [HTTPCallbackVerifier]. val pattern = - """^http:\/\/localhost:${config.httpCallbackVerifierPort}\/EM_\d+$""".toRegex() + """^http:\/\/localhost:${config.httpCallbackVerifierPort}\/EM_SSRF_\d+$""".toRegex() return pattern.matches(value) } @@ -76,7 +76,7 @@ class HttpCallbackVerifier { fun generateCallbackLink(name: String): String { // FIXME: sink/EM_0 <- slash get replaced with a comma at some point, which fails // the verification based on the metadata - val ssrfPath = "/EM_${counter++}" + val ssrfPath = "/EM_SSRF_${counter++}" wireMockServer!!.stubFor( WireMock.any(WireMock.urlEqualTo(ssrfPath)) From fa97ac38c01a5fbda9ae834c9046e6d3901fbecb Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:57:53 +0530 Subject: [PATCH 28/52] clean-up --- .../problem/rest/service/fitness/AbstractRestFitness.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt index 7a92d38048..62f8b36cf0 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt @@ -40,6 +40,7 @@ import org.evomaster.core.problem.rest.service.AIResponseClassifier import org.evomaster.core.problem.rest.service.sampler.AbstractRestSampler import org.evomaster.core.problem.rest.service.sampler.AbstractRestSampler.Companion.CALL_TO_SWAGGER_ID import org.evomaster.core.problem.rest.service.RestIndividualBuilder +import org.evomaster.core.problem.security.service.HttpCallbackVerifier import org.evomaster.core.problem.security.service.SSRFAnalyser import org.evomaster.core.problem.util.ParserDtoUtil import org.evomaster.core.remote.HttpClientFactory @@ -82,6 +83,9 @@ abstract class AbstractRestFitness : HttpWsFitness() { @Inject protected lateinit var ssrfAnalyser: SSRFAnalyser + @Inject + protected lateinit var httpCallbackVerifier: HttpCallbackVerifier + @Inject protected lateinit var responsePool: DataPool @@ -734,7 +738,8 @@ abstract class AbstractRestFitness : HttpWsFitness() { // FIXME: Code never reach this when we recompute the fitness under SSRFAnalyser // When the execution reach this during recomputing fitness, [HttpCallbackVerifier] - // seems to be [null]. Due to that the method will never return true if any calls made. + // WireMock seems to be [null]. + // Due to that the method will never return true if any calls made. if (config.security && config.ssrf) { if (ssrfAnalyser.anyCallsMadeToHTTPVerifier(a)) { // Code reach this point during the search, which is unnecessary during search From 9b5f26380e80b5d91b98105a8138b86462d2ecd4 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:58:10 +0530 Subject: [PATCH 29/52] disabled e2e --- .../spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 16a393b210..88ba76403d 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } -// @Disabled + @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( @@ -41,7 +41,7 @@ class SSRFQueryEMTest: SpringTestBase() { Assertions.assertTrue(solution.individuals.isNotEmpty()) -// assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/query", "OK") + assertHasAtLeastOne(solution, HttpVerb.GET, 200, "/api/query", "OK") } } } From 20093d5edd9ca4fa6607551721e6334861b5dd31 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 12:03:01 +0530 Subject: [PATCH 30/52] clean-up --- .../core/problem/rest/service/fitness/AbstractRestFitness.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt index 62f8b36cf0..c84a7275c6 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt @@ -83,9 +83,6 @@ abstract class AbstractRestFitness : HttpWsFitness() { @Inject protected lateinit var ssrfAnalyser: SSRFAnalyser - @Inject - protected lateinit var httpCallbackVerifier: HttpCallbackVerifier - @Inject protected lateinit var responsePool: DataPool From 95f59a2fb43a5be8f149e029aae01fda661e7a05 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:12:14 +0530 Subject: [PATCH 31/52] trying to fix --- .../main/kotlin/org/evomaster/core/Main.kt | 2 +- .../security/service/HttpCallbackVerifier.kt | 23 +++++++----- .../problem/security/service/SSRFAnalyser.kt | 35 +++++++++++-------- .../v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/Main.kt b/core/src/main/kotlin/org/evomaster/core/Main.kt index 5a7e9c545a..f22a22384e 100644 --- a/core/src/main/kotlin/org/evomaster/core/Main.kt +++ b/core/src/main/kotlin/org/evomaster/core/Main.kt @@ -1021,7 +1021,7 @@ class Main { private fun resetHTTPCallbackVerifier(injector: Injector) { val httpCallbackVerifier = injector.getInstance(HttpCallbackVerifier::class.java) - httpCallbackVerifier.reset() + httpCallbackVerifier.stop() } } } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index 2f92b11202..f3bac25b30 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -42,18 +42,24 @@ class HttpCallbackVerifier { @PreDestroy fun destroy() { - resetHTTPVerifier() + stop() } - fun initWireMockServer() { + fun prepare() { + if (isActive) { + return + } + try { val config = WireMockConfiguration() .extensions(ResponseTemplateTransformer(false)) .port(config.httpCallbackVerifierPort) - wireMockServer = WireMockServer(config) - wireMockServer!!.start() - wireMockServer!!.stubFor(getDefaultStub()) + val wm = WireMockServer(config) + wm.start() + wm.stubFor(getDefaultStub()) + + wireMockServer = wm } catch (e: Exception) { throw RuntimeException( e.message + @@ -102,7 +108,8 @@ class HttpCallbackVerifier { */ fun verify(name: String): Boolean { if (isActive) { - wireMockServer!!.allServeEvents + wireMockServer!! + .allServeEvents .filter { event -> event.wasMatched } .forEach { e -> val matched = e.stubMapping.metadata @@ -115,14 +122,14 @@ class HttpCallbackVerifier { return false } - fun resetHTTPVerifier() { + fun reset() { wireMockServer?.resetAll() wireMockServer?.stubFor(getDefaultStub()) actionCallbackLinkMapping.clear() counter = 0 } - fun reset() { + fun stop() { counter = 0 wireMockServer?.stop() wireMockServer = null diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 7e432829c8..31b203ce81 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -80,9 +80,8 @@ class SSRFAnalyser { } } - fun apply(): Solution { - LoggingUtil.Companion.getInfoLogger().info("Applying {}", SSRFAnalyser::class.simpleName) + LoggingUtil.getInfoLogger().info("Applying {}", SSRFAnalyser::class.simpleName) // extract individuals from the archive val individuals = this.archive.extractSolution().individuals @@ -101,18 +100,16 @@ class SSRFAnalyser { // The below steps are generic, for future extensions can be // accommodated easily under these common steps. + if (httpCallbackVerifier.isActive) { + // Reset before execution + httpCallbackVerifier.reset() + } else { + httpCallbackVerifier.prepare() + } + // Classify endpoints with potential vulnerability classes classify() - if (actionVulnerabilityMapping.isNotEmpty()) { - if (httpCallbackVerifier.isActive) { - // Reset before execution - httpCallbackVerifier.resetHTTPVerifier() - } else { - httpCallbackVerifier.initWireMockServer() - } - } - // execute analyse() @@ -139,11 +136,19 @@ class SSRFAnalyser { val hasCallBackURL = GeneUtils .getAllStringFields(action.parameters) .any { gene -> - httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) - } + httpCallbackVerifier.isCallbackURL(gene.getValueAsRawString()) + } if (hasCallBackURL) { - return httpCallbackVerifier.verify(action.getName()) + // FIXME: When the code reaches this point during SSRF phase + // WireMock is null, due to that this will return false. + // Which will not add the fault category. + // However, I can see the WireMock get initiated even before + // reaching this point. + // I suspected something to do with the dependency injection. + // I tried moving the WireMock inside this class, still the same. + val x = httpCallbackVerifier.verify(action.getName()) + return x } return false @@ -254,7 +259,7 @@ class SSRFAnalyser { ) } - return answer != null && answer.answer == SSRFUtil.Companion.SSRF_PROMPT_ANSWER_FOR_POSSIBILITY + return answer != null && answer.answer == SSRFUtil.SSRF_PROMPT_ANSWER_FOR_POSSIBILITY } /** diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 88ba76403d..bc214efc4c 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } - @Disabled +// @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( From b7193996d90f4e823de309bc43fbeee202d50b17 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:14:29 +0530 Subject: [PATCH 32/52] minor change --- core/src/main/kotlin/org/evomaster/core/Main.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/Main.kt b/core/src/main/kotlin/org/evomaster/core/Main.kt index f22a22384e..12fccc34e8 100644 --- a/core/src/main/kotlin/org/evomaster/core/Main.kt +++ b/core/src/main/kotlin/org/evomaster/core/Main.kt @@ -261,7 +261,7 @@ class Main { resetExternalServiceHandler(injector) - resetHTTPCallbackVerifier(injector) + stopHTTPCallbackVerifier(injector) val statistics = injector.getInstance(Statistics::class.java) val data = statistics.getData(solution) @@ -1019,7 +1019,7 @@ class Main { externalServiceHandler.reset() } - private fun resetHTTPCallbackVerifier(injector: Injector) { + private fun stopHTTPCallbackVerifier(injector: Injector) { val httpCallbackVerifier = injector.getInstance(HttpCallbackVerifier::class.java) httpCallbackVerifier.stop() } From 25aa903891bf2594efedeb63327449db2a2befce Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:17:17 +0530 Subject: [PATCH 33/52] clean-up --- .../core/problem/rest/service/fitness/AbstractRestFitness.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt index c84a7275c6..2a73d50138 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt @@ -40,7 +40,6 @@ import org.evomaster.core.problem.rest.service.AIResponseClassifier import org.evomaster.core.problem.rest.service.sampler.AbstractRestSampler import org.evomaster.core.problem.rest.service.sampler.AbstractRestSampler.Companion.CALL_TO_SWAGGER_ID import org.evomaster.core.problem.rest.service.RestIndividualBuilder -import org.evomaster.core.problem.security.service.HttpCallbackVerifier import org.evomaster.core.problem.security.service.SSRFAnalyser import org.evomaster.core.problem.util.ParserDtoUtil import org.evomaster.core.remote.HttpClientFactory From b90473aeb16b0baa5e94be7a1271f8de5dcff3d5 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:20:10 +0530 Subject: [PATCH 34/52] disabled e2e --- .../spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index bc214efc4c..88ba76403d 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } -// @Disabled + @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( From eb7c333e651449e2b81585cebe8d5b5ac6d4d1bc Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:03:30 +0530 Subject: [PATCH 35/52] fix --- .../core/problem/rest/service/module/RestBaseModule.kt | 3 ++- .../spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/module/RestBaseModule.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/module/RestBaseModule.kt index 35497e4a2f..fe39bfa2b8 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/module/RestBaseModule.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/module/RestBaseModule.kt @@ -18,6 +18,7 @@ import org.evomaster.core.seeding.service.rest.PirToRest open class RestBaseModule : EnterpriseModule() { override fun configure() { + super.configure() bind(TestCaseWriter::class.java) .to(RestTestCaseWriter::class.java) @@ -59,4 +60,4 @@ open class RestBaseModule : EnterpriseModule() { .asEagerSingleton() } -} \ No newline at end of file +} diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 88ba76403d..bc214efc4c 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } - @Disabled +// @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( From 9a056fc92172a1be80e2ea1e07fe8926d54a078b Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:46:54 +0530 Subject: [PATCH 36/52] disabled e2e --- .../spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index bc214efc4c..88ba76403d 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } -// @Disabled + @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( From ea59b44532ecbd9076052eb73505325e2a907c2f Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 00:44:11 +0530 Subject: [PATCH 37/52] fix for out of memory issue --- .../core/problem/security/service/SSRFAnalyser.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 31b203ce81..c27eb8a428 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -73,12 +73,13 @@ class SSRFAnalyser { loadURLParamNamesFromFile() } - @PreDestroy - private fun preDestroy() { - if (config.ssrf) { - actionVulnerabilityMapping.clear() - } - } +// FIXME: PreDestroy case out of memory problems in RestIndividualResourceTest +// @PreDestroy +// private fun preDestroy() { +// if (config.ssrf) { +// actionVulnerabilityMapping.clear() +// } +// } fun apply(): Solution { LoggingUtil.getInfoLogger().info("Applying {}", SSRFAnalyser::class.simpleName) From b4b525596c2e042e4d190ee4e8d9ae16c26d5901 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 09:31:24 +0530 Subject: [PATCH 38/52] clean-up --- .../rest/service/fitness/AbstractRestFitness.kt | 5 ----- .../security/service/HttpCallbackVerifier.kt | 4 +++- .../problem/security/service/SSRFAnalyser.kt | 17 +++-------------- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt index 2a73d50138..7b27a8061b 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rest/service/fitness/AbstractRestFitness.kt @@ -732,13 +732,8 @@ abstract class AbstractRestFitness : HttpWsFitness() { responseClassifier.updateModel(a, rcr) } - // FIXME: Code never reach this when we recompute the fitness under SSRFAnalyser - // When the execution reach this during recomputing fitness, [HttpCallbackVerifier] - // WireMock seems to be [null]. - // Due to that the method will never return true if any calls made. if (config.security && config.ssrf) { if (ssrfAnalyser.anyCallsMadeToHTTPVerifier(a)) { - // Code reach this point during the search, which is unnecessary during search rcr.setVulnerableForSSRF(true) } } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index f3bac25b30..24aa82f20b 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -42,7 +42,9 @@ class HttpCallbackVerifier { @PreDestroy fun destroy() { - stop() + if (config.ssrf) { + stop() + } } fun prepare() { diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index c27eb8a428..2a650ad8c6 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -21,7 +21,6 @@ import org.evomaster.core.search.service.FitnessFunction import org.slf4j.Logger import org.slf4j.LoggerFactory import javax.annotation.PostConstruct -import javax.annotation.PreDestroy class SSRFAnalyser { @@ -69,8 +68,9 @@ class SSRFAnalyser { @PostConstruct fun init() { - log.debug("Initializing {}", SSRFAnalyser::class.simpleName) - loadURLParamNamesFromFile() + if (config.ssrf) { + log.debug("Initializing {}", SSRFAnalyser::class.simpleName) + } } // FIXME: PreDestroy case out of memory problems in RestIndividualResourceTest @@ -141,13 +141,6 @@ class SSRFAnalyser { } if (hasCallBackURL) { - // FIXME: When the code reaches this point during SSRF phase - // WireMock is null, due to that this will return false. - // Which will not add the fault category. - // However, I can see the WireMock get initiated even before - // reaching this point. - // I suspected something to do with the dependency injection. - // I tried moving the WireMock inside this class, still the same. val x = httpCallbackVerifier.verify(action.getName()) return x } @@ -365,8 +358,4 @@ class SSRFAnalyser { } } } - - private fun loadURLParamNamesFromFile() { - // TODO - } } From b0eff311a5919953261e97c496bb81b06eb83aff Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 09:34:50 +0530 Subject: [PATCH 39/52] comments --- .../core/problem/security/service/SSRFAnalyser.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 2a650ad8c6..afd069bda4 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -58,8 +58,17 @@ class SSRFAnalyser { */ private lateinit var individualsInSolution: List> + /** + * Regex pattern to match if the given string has these words. + * i - case-insensitive + * g - global, find all the matches not the first one + */ private val urlRegexPattern: Regex = Regex("/url|source|remote|target/ig") + /** + * Possible URL variable names. + * TODO: Can load from a file. + */ private val potentialUrlParamNames: List = listOf("url", "source", "target", "datasource") companion object { From ae15a56546560f220e8302591198a858bba26ea8 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 09:36:09 +0530 Subject: [PATCH 40/52] clean-up --- .../core/problem/security/service/SSRFAnalyser.kt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index afd069bda4..95f422c6ee 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -162,15 +162,6 @@ class SSRFAnalyser { * potential security classes scope */ fun classify() { - // TODO: We need to store word bag of potential input names - // if we are going to classify using the variable names. - // Other approach is to rely on the API doc with explicit - // definitions of potential vulnerability classes. - // This is for SSRF. - // For SQLi we can consider individuals with SQL actions. - // Are we going mark potential vulnerability classes as one time - // job or going to evaluate each time (which is costly). - individualsInSolution.forEach { evaluatedIndividual -> evaluatedIndividual.evaluatedMainActions().forEach { a -> val action = a.action @@ -323,9 +314,6 @@ class SSRFAnalyser { copy.seeMainExecutableActions().forEach { action -> action.parameters.forEach { param -> - // TODO: Do we need to only update the StringGene? - // TODO: Tests are generated when only update the primaryGene, - // when use seeGenes() nothing generated. param.primaryGene().getViewOfChildren().forEach { gene -> updateGeneWithCallbackURL(action.getName(), gene, callbackURL) } From b2c28ad7b2b6cf3a741f0e4ace07ef9b4c0aaf30 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 12:46:43 +0530 Subject: [PATCH 41/52] fix --- .../problem/security/data/ActionFaultMapping.kt | 13 +++++++++++-- .../problem/security/data/InputFaultMapping.kt | 5 +++++ .../security/service/HttpCallbackVerifier.kt | 7 +++++-- .../core/problem/security/service/SSRFAnalyser.kt | 14 ++++++++++++-- .../v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt index 14b67e7c87..6dffd1a4ea 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt @@ -1,6 +1,7 @@ package org.evomaster.core.problem.security.data import com.webfuzzing.commons.faults.FaultCategory +import org.evomaster.core.problem.enterprise.DetectedFault /** * [ActionFaultMapping] represents the [Action] and related [Param] with security faults. @@ -17,8 +18,6 @@ class ActionFaultMapping ( var isVulnerable = false - var isExploitable = false - /** * TODO: This is temporary to use it in the test cases. */ @@ -32,4 +31,14 @@ class ActionFaultMapping ( fun addSecurityFaultCategory(faultCategory: FaultCategory) { securityFaults.add(faultCategory) } + + fun hasVulnerableParameterForSSRF(name: String): Boolean { + if (params.containsKey(name)) { + if (params[name]!!.isVulnerableForSSRF()) { + return true + } + } + + return false + } } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt index e198ff468d..ff04f35bde 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt @@ -1,5 +1,6 @@ package org.evomaster.core.problem.security.data +import com.webfuzzing.commons.faults.DefinedFaultCategory import com.webfuzzing.commons.faults.FaultCategory class InputFaultMapping ( @@ -16,4 +17,8 @@ class InputFaultMapping ( securityFaults.add(faultCategory) } + fun isVulnerableForSSRF(): Boolean { + return securityFaults.contains(DefinedFaultCategory.SSRF) + } + } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index 24aa82f20b..853d414400 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -31,6 +31,9 @@ class HttpCallbackVerifier { companion object { private val log: Logger = LoggerFactory.getLogger(HttpCallbackVerifier::class.java) + + const val DEFAULT_RESPONSE_STATUS_CODE = 200 + const val DEFAULT_RESPONSE_BODY = "Gotcha!" } @PostConstruct @@ -92,8 +95,8 @@ class HttpCallbackVerifier { .atPriority(1) .willReturn( WireMock.aResponse() - .withStatus(200) - .withBody("OK") + .withStatus(DEFAULT_RESPONSE_STATUS_CODE) + .withBody(DEFAULT_RESPONSE_BODY) ) ) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 95f422c6ee..d338cce0b2 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -142,7 +142,6 @@ class SSRFAnalyser { should check the content of rcr result */ - val hasCallBackURL = GeneUtils .getAllStringFields(action.parameters) .any { gene -> @@ -212,6 +211,18 @@ class SSRFAnalyser { return null } + /** + * To check whether [Action] has any faults for SSRF. + */ + fun isVulnerableParameter(action: String, param: String): Boolean { + if (actionVulnerabilityMapping.containsKey(action)) { + if (actionVulnerabilityMapping[action]!!.hasVulnerableParameterForSSRF(param)) { + return true + } + } + return false + } + /** * A private method to identify parameter is a potentially holds URL value * using a Regex based approach. @@ -336,7 +347,6 @@ class SSRFAnalyser { val result = httpCallbackVerifier.verify(action.getName()) if (result) { val actionMapping = actionVulnerabilityMapping.getValue(action.getName()) - actionMapping.isExploitable = true actionMapping.addSecurityFaultCategory(DefinedFaultCategory.SSRF) // Create a testing target archive.addIfNeeded(executedIndividual) diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 88ba76403d..bc214efc4c 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } - @Disabled +// @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( From e3c66f9481d692546c2577ba2e8c6503f2c459c3 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 12:51:50 +0530 Subject: [PATCH 42/52] clean-up --- .../core/problem/security/service/HttpCallbackVerifier.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index 853d414400..e171ce1c7a 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -32,8 +32,8 @@ class HttpCallbackVerifier { companion object { private val log: Logger = LoggerFactory.getLogger(HttpCallbackVerifier::class.java) - const val DEFAULT_RESPONSE_STATUS_CODE = 200 - const val DEFAULT_RESPONSE_BODY = "Gotcha!" + const val SSRF_RESPONSE_STATUS_CODE = 200 + const val SSRF_RESPONSE_BODY = "SSRF" } @PostConstruct @@ -95,8 +95,8 @@ class HttpCallbackVerifier { .atPriority(1) .willReturn( WireMock.aResponse() - .withStatus(DEFAULT_RESPONSE_STATUS_CODE) - .withBody(DEFAULT_RESPONSE_BODY) + .withStatus(SSRF_RESPONSE_STATUS_CODE) + .withBody(SSRF_RESPONSE_BODY) ) ) From 047f8c42acb747e0bb008001dfcdd10a80e039da Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 12:58:28 +0530 Subject: [PATCH 43/52] fix for HttpCallbackVerifier --- .../core/problem/security/service/HttpCallbackVerifier.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index e171ce1c7a..3b86bd7582 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -87,6 +87,12 @@ class HttpCallbackVerifier { fun generateCallbackLink(name: String): String { // FIXME: sink/EM_0 <- slash get replaced with a comma at some point, which fails // the verification based on the metadata + if (actionCallbackLinkMapping.containsKey(name)) { + if (actionCallbackLinkMapping[name] != null) { + return actionCallbackLinkMapping[name]!! + } + } + val ssrfPath = "/EM_SSRF_${counter++}" wireMockServer!!.stubFor( From b223ca800374fb78a75a37cde2608c5c88042577 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 13:01:55 +0530 Subject: [PATCH 44/52] clean-up --- .../core/problem/security/data/ActionFaultMapping.kt | 12 +----------- .../core/problem/security/data/InputFaultMapping.kt | 8 +------- .../core/problem/security/service/SSRFAnalyser.kt | 12 ------------ 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt index 6dffd1a4ea..82dd8d6160 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt @@ -1,13 +1,12 @@ package org.evomaster.core.problem.security.data import com.webfuzzing.commons.faults.FaultCategory -import org.evomaster.core.problem.enterprise.DetectedFault /** * [ActionFaultMapping] represents the [Action] and related [Param] with security faults. * This used in [SSRFAnalyser]. */ -class ActionFaultMapping ( +class ActionFaultMapping( val name: String, ) { @@ -32,13 +31,4 @@ class ActionFaultMapping ( securityFaults.add(faultCategory) } - fun hasVulnerableParameterForSSRF(name: String): Boolean { - if (params.containsKey(name)) { - if (params[name]!!.isVulnerableForSSRF()) { - return true - } - } - - return false - } } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt index ff04f35bde..06d32c80c9 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt @@ -1,9 +1,8 @@ package org.evomaster.core.problem.security.data -import com.webfuzzing.commons.faults.DefinedFaultCategory import com.webfuzzing.commons.faults.FaultCategory -class InputFaultMapping ( +class InputFaultMapping( val name: String, val description: String? ) { @@ -16,9 +15,4 @@ class InputFaultMapping ( fun addSecurityFaultCategory(faultCategory: FaultCategory) { securityFaults.add(faultCategory) } - - fun isVulnerableForSSRF(): Boolean { - return securityFaults.contains(DefinedFaultCategory.SSRF) - } - } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index d338cce0b2..939cd9e1bc 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -211,18 +211,6 @@ class SSRFAnalyser { return null } - /** - * To check whether [Action] has any faults for SSRF. - */ - fun isVulnerableParameter(action: String, param: String): Boolean { - if (actionVulnerabilityMapping.containsKey(action)) { - if (actionVulnerabilityMapping[action]!!.hasVulnerableParameterForSSRF(param)) { - return true - } - } - return false - } - /** * A private method to identify parameter is a potentially holds URL value * using a Regex based approach. From d78e6041080e04f2e401d0cd528c2a161fdcacae Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 13:08:39 +0530 Subject: [PATCH 45/52] more updates --- .../security/service/HttpCallbackVerifier.kt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt index 3b86bd7582..2fe59aeb81 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/HttpCallbackVerifier.kt @@ -25,6 +25,8 @@ class HttpCallbackVerifier { */ private var actionCallbackLinkMapping: MutableMap = mutableMapOf() + private var actionStubMapping: MutableMap = mutableMapOf() + val isActive: Boolean get() = wireMockServer != null && wireMockServer!!.isRunning private var counter: Long = 0 @@ -93,10 +95,10 @@ class HttpCallbackVerifier { } } - val ssrfPath = "/EM_SSRF_${counter++}" + val stub = "/EM_SSRF_${counter++}" wireMockServer!!.stubFor( - WireMock.any(WireMock.urlEqualTo(ssrfPath)) + WireMock.any(WireMock.urlEqualTo(stub)) .withMetadata(Metadata.metadata().attr("ssrf", name)) .atPriority(1) .willReturn( @@ -106,13 +108,24 @@ class HttpCallbackVerifier { ) ) - val link = "http://localhost:${wireMockServer!!.port()}$ssrfPath" + val link = "http://localhost:${wireMockServer!!.port()}$stub" actionCallbackLinkMapping[name] = link + actionStubMapping[name] = stub return link } + /** + * WireMock stub assigned for [Action]. + */ + fun getStubForAction(name: String): String? { + if (actionStubMapping.containsKey(name)) { + return actionStubMapping[name] + } + return null + } + /** * @param name represents the Action name * During stub creation, stubs are tagged with Action name in the metadata. From fb3f05289154bab7dfca152d27cc2d1264c0c24d Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 13:19:52 +0530 Subject: [PATCH 46/52] clean-up --- .../problem/security/data/ActionFaultMapping.kt | 13 ++++++++----- .../core/problem/security/data/InputFaultMapping.kt | 5 +++++ .../core/problem/security/service/SSRFAnalyser.kt | 8 +------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt index 82dd8d6160..36e0d4ef78 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/data/ActionFaultMapping.kt @@ -17,11 +17,6 @@ class ActionFaultMapping( var isVulnerable = false - /** - * TODO: This is temporary to use it in the test cases. - */ - var httpCallbackURL: String? = null - /** * Holds potential security faults for the [Action]. */ @@ -31,4 +26,12 @@ class ActionFaultMapping( securityFaults.add(faultCategory) } + fun getVulnerableParameterName(): String? { + val params = params.filter { it.value.hasSSRFFaults() } + if (params.isNotEmpty()) { + return params.keys.first() + } + return null + } + } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt index 06d32c80c9..8a37ce801b 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/data/InputFaultMapping.kt @@ -1,5 +1,6 @@ package org.evomaster.core.problem.security.data +import com.webfuzzing.commons.faults.DefinedFaultCategory import com.webfuzzing.commons.faults.FaultCategory class InputFaultMapping( @@ -15,4 +16,8 @@ class InputFaultMapping( fun addSecurityFaultCategory(faultCategory: FaultCategory) { securityFaults.add(faultCategory) } + + fun hasSSRFFaults(): Boolean { + return securityFaults.contains(DefinedFaultCategory.SSRF) + } } diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 939cd9e1bc..51a83f0a82 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -199,12 +199,7 @@ class SSRFAnalyser { if (actionVulnerabilityMapping.containsKey(action.getName())) { val mapping = actionVulnerabilityMapping[action.getName()] if (mapping != null) { - val param = mapping.params.filter { - it.value.securityFaults.contains( - DefinedFaultCategory.SSRF - ) - } - return param.keys.first() + return mapping.getVulnerableParameterName() } } @@ -331,7 +326,6 @@ class SSRFAnalyser { executedIndividual: EvaluatedIndividual, callbackURL: String ) { - actionVulnerabilityMapping.getValue(action.getName()).httpCallbackURL = callbackURL val result = httpCallbackVerifier.verify(action.getName()) if (result) { val actionMapping = actionVulnerabilityMapping.getValue(action.getName()) From 23d935fe01ed6567ff435ebf989de378ff788df3 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 14:29:16 +0530 Subject: [PATCH 47/52] minor addition --- .../evomaster/core/problem/security/service/SSRFAnalyser.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 51a83f0a82..c683c3e5b4 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -69,7 +69,7 @@ class SSRFAnalyser { * Possible URL variable names. * TODO: Can load from a file. */ - private val potentialUrlParamNames: List = listOf("url", "source", "target", "datasource") + private val potentialUrlParamNames: List = listOf("url", "source", "target", "datasource", "referer") companion object { private val log: Logger = LoggerFactory.getLogger(SSRFAnalyser::class.java) @@ -149,8 +149,7 @@ class SSRFAnalyser { } if (hasCallBackURL) { - val x = httpCallbackVerifier.verify(action.getName()) - return x + return httpCallbackVerifier.verify(action.getName()) } return false From 8acd27de9b05052af63d89277832277be9763399 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 15:15:39 +0530 Subject: [PATCH 48/52] regex fix --- .../core/problem/security/service/SSRFAnalyser.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index c683c3e5b4..02a32740aa 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -63,7 +63,8 @@ class SSRFAnalyser { * i - case-insensitive * g - global, find all the matches not the first one */ - private val urlRegexPattern: Regex = Regex("/url|source|remote|target/ig") + private val urlRegexPattern: Regex = "\\w*(url|source|remote|target|href|uri|link|endpoint|api|path|host)\\w*" + .toRegex(RegexOption.IGNORE_CASE) /** * Possible URL variable names. @@ -213,12 +214,11 @@ class SSRFAnalyser { if (potentialUrlParamNames.contains(name.lowercase())) { return true } - - if (name.matches(urlRegexPattern)) { + if (urlRegexPattern.containsMatchIn(name)) { return true } if (description != null) { - if (description.matches(urlRegexPattern)) { + if (urlRegexPattern.containsMatchIn(description)) { return true } } From be6672bcd273fcc3ddc868391c006d3ba50200c4 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 19:18:34 +0530 Subject: [PATCH 49/52] disabled e2e --- .../spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index bc214efc4c..88ba76403d 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -21,7 +21,7 @@ class SSRFQueryEMTest: SpringTestBase() { } } -// @Disabled + @Disabled @Test fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( From 224a57a8e572f3aa584cd9c8de6c4c65c3a94318 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 23:20:28 +0530 Subject: [PATCH 50/52] minor --- .../org/evomaster/core/problem/security/service/SSRFAnalyser.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 02a32740aa..243d448b2d 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -60,8 +60,6 @@ class SSRFAnalyser { /** * Regex pattern to match if the given string has these words. - * i - case-insensitive - * g - global, find all the matches not the first one */ private val urlRegexPattern: Regex = "\\w*(url|source|remote|target|href|uri|link|endpoint|api|path|host)\\w*" .toRegex(RegexOption.IGNORE_CASE) From 0a1a1854ba2de008624b5e64ef3cdf46e88c8c87 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Wed, 3 Sep 2025 23:22:51 +0530 Subject: [PATCH 51/52] comments --- .../org/evomaster/core/problem/security/service/SSRFAnalyser.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt index 243d448b2d..ee72701cbc 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/security/service/SSRFAnalyser.kt @@ -59,7 +59,7 @@ class SSRFAnalyser { private lateinit var individualsInSolution: List> /** - * Regex pattern to match if the given string has these words. + * Regex pattern to match if the given string has these words anywhere on the string. */ private val urlRegexPattern: Regex = "\\w*(url|source|remote|target|href|uri|link|endpoint|api|path|host)\\w*" .toRegex(RegexOption.IGNORE_CASE) From 5eeca128e68efb1dcb25c5ce8734c4c0315137c8 Mon Sep 17 00:00:00 2001 From: seran <7030273+seran@users.noreply.github.com> Date: Thu, 4 Sep 2025 00:04:09 +0530 Subject: [PATCH 52/52] minor updates --- .../spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt | 2 +- .../spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt | 2 +- .../spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt index 62f4d81e11..ae0b1da645 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/base/SSRFBaseEMTest.kt @@ -27,7 +27,7 @@ class SSRFBaseEMTest : SpringTestBase() { fun testSSRFEM() { runTestHandlingFlakyAndCompilation( "SSRFBaseEMTest", - 200, + 50, ) { args: MutableList -> // If mocking enabled, it'll spin new services each time when there is a valid URL. diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt index 00717206cf..838f7b814c 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/header/SSRFHeaderEMTest.kt @@ -26,7 +26,7 @@ class SSRFHeaderEMTest: SpringTestBase() { fun testSSRFHeader() { runTestHandlingFlakyAndCompilation( "SSRFHeaderEMTest", - 80, + 30, ) { args: MutableList -> // If mocking enabled, it'll spin new services each time when there is a valid URL. diff --git a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt index 88ba76403d..ee38697050 100644 --- a/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt +++ b/e2e-tests/spring-rest-openapi-v3/src/test/kotlin/org/evomaster/e2etests/spring/openapi/v3/security/ssrf/query/SSRFQueryEMTest.kt @@ -26,7 +26,7 @@ class SSRFQueryEMTest: SpringTestBase() { fun testSSRFQuery() { runTestHandlingFlakyAndCompilation( "SSRFQueryEMTest", - 80, + 30, ) { args: MutableList -> // If mocking enabled, it'll spin new services each time when there is a valid URL.