diff --git a/.github/workflows/dast-zap-test.yml b/.github/workflows/dast-zap-test.yml
new file mode 100644
index 000000000..2201c43bb
--- /dev/null
+++ b/.github/workflows/dast-zap-test.yml
@@ -0,0 +1,33 @@
+name: DAST with ZAP
+
+on:
+ pull_request:
+ branches: [master]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ test-dast:
+ name: DAST test with ZAP
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up JDK 19
+ uses: actions/setup-java@v3
+ with:
+ java-version: "19"
+ distribution: "temurin"
+ - name: Clean install
+ run: ./mvnw clean install
+ - name: Start wrongsecrets
+ run: nohup ./mvnw spring-boot:run -Dspring-boot.run.profiles=without-vault &
+ - name: ZAP Scan
+ uses: zaproxy/action-baseline@v0.7.0
+ with:
+ allow_issue_writing: false
+ docker_name: "owasp/zap2docker-stable"
+ target: "http://localhost:8080"
+ rules_file_name: .zap/rule-config.tsv
+ fail_action: true
diff --git a/.zap/rule-config.tsv b/.zap/rule-config.tsv
new file mode 100644
index 000000000..765c0a9f5
--- /dev/null
+++ b/.zap/rule-config.tsv
@@ -0,0 +1,11 @@
+10027 IGNORE (Information Disclosure - Suspicious Comments)
+10031 IGNORE (Informational User Controllable HTML Element Attribute (Potential XSS))
+10049 IGNORE (Non-Storable Content)
+10054 IGNORE (Cookie without SameSite Attribute)
+10055 IGNORE (CSP: Wildcard Directive)
+10055 IGNORE (CSP: script-src unsafe-inline)
+10055 IGNORE (CSP: style-src unsafe-inline)
+10063 IGNORE (Permissions Policy Header Not Set)
+10109 IGNORE (Modern Web Application)
+10110 IGNORE (Dangerous JS Functions)
+90033 IGNORE (Loosely Scoped Cookie)
diff --git a/README.md b/README.md
index 1e5599d64..cd5c0be4d 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ Welcome to the OWASP WrongSecrets p0wnable app. With this app, we have packed va
secrets. These can help you to realize whether your secret management is ok. The challenge is to find all the different
secrets by means of various tools and techniques.
-Can you solve all the 27 challenges?
+Can you solve all the 28 challenges?
![screenshotOfChallenge1](/images/screenshot.png)
diff --git a/src/main/java/org/owasp/wrongsecrets/WrongSecretsApplication.java b/src/main/java/org/owasp/wrongsecrets/WrongSecretsApplication.java
index 426af9a3b..ab55c222f 100644
--- a/src/main/java/org/owasp/wrongsecrets/WrongSecretsApplication.java
+++ b/src/main/java/org/owasp/wrongsecrets/WrongSecretsApplication.java
@@ -19,7 +19,7 @@ public static void main(String[] args) {
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public InMemoryScoreCard scoreCard() {
- return new InMemoryScoreCard(27);
+ return new InMemoryScoreCard(28);
}
diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/ChallengesController.java b/src/main/java/org/owasp/wrongsecrets/challenges/ChallengesController.java
index 1d045152c..da9f79396 100644
--- a/src/main/java/org/owasp/wrongsecrets/challenges/ChallengesController.java
+++ b/src/main/java/org/owasp/wrongsecrets/challenges/ChallengesController.java
@@ -6,6 +6,7 @@
import org.owasp.wrongsecrets.challenges.docker.Challenge0;
import org.owasp.wrongsecrets.challenges.docker.Challenge8;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.codec.Hex;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@@ -13,6 +14,7 @@
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.server.ResponseStatusException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
@@ -53,6 +55,14 @@ public ChallengesController(ScoreCard scoreCard, List challenges, R
this.runtimeEnvironment = runtimeEnvironment;
}
+ private boolean checkId(int id) {
+ // If the id is either negative or larger than the amount of challenges, return false.
+ if (id < 0 || id >= challenges.size()) {
+ return false;
+ }
+ return true;
+ }
+
@GetMapping
public String explanation(@PathVariable Integer id) {
return challenges.get(id).getExplanation();
@@ -71,6 +81,11 @@ public String spoiler(Model model, @PathVariable Integer id) {
@GetMapping("/challenge/{id}")
public String challenge(Model model, @PathVariable Integer id) {
+ if (!checkId(id)) {
+ throw new ResponseStatusException(
+ HttpStatus.NOT_FOUND, "challenge not found"
+ );
+ }
var challenge = challenges.get(id);
model.addAttribute("challengeForm", new ChallengeForm(""));
@@ -98,6 +113,11 @@ public String challenge(Model model, @PathVariable Integer id) {
@PostMapping(value = "/challenge/{id}", params = "action=reset")
public String reset(@ModelAttribute ChallengeForm challengeForm, @PathVariable Integer id, Model model) {
+ if (!checkId(id)) {
+ throw new ResponseStatusException(
+ HttpStatus.NOT_FOUND, "challenge not found"
+ );
+ }
var challenge = challenges.get(id);
scoreCard.reset(challenge.getChallenge());
@@ -110,6 +130,11 @@ public String reset(@ModelAttribute ChallengeForm challengeForm, @PathVariable I
@PostMapping(value = "/challenge/{id}", params = "action=submit")
public String postController(@ModelAttribute ChallengeForm challengeForm, Model model, @PathVariable Integer id) {
+ if (!checkId(id)) {
+ throw new ResponseStatusException(
+ HttpStatus.NOT_FOUND, "challenge not found"
+ );
+ }
var challenge = challenges.get(id);
if (!challenge.isChallengeEnabled()) {
diff --git a/src/test/java/org/owasp/wrongsecrets/ChallengeAPiControllerTest.java b/src/test/java/org/owasp/wrongsecrets/ChallengeAPiControllerTest.java
index 821f8443d..86ec1c8dc 100644
--- a/src/test/java/org/owasp/wrongsecrets/ChallengeAPiControllerTest.java
+++ b/src/test/java/org/owasp/wrongsecrets/ChallengeAPiControllerTest.java
@@ -39,5 +39,5 @@ void shouldGetListOfChallenges() {
}
/*
-"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "soruce", "useragent" : "agent", "referer" : "referer", "location" : "locatoin"}}
+"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "source", "useragent" : "agent", "referer" : "referer", "location" : "location"}}
*/
diff --git a/src/test/java/org/owasp/wrongsecrets/ChallengesControllerTest.java b/src/test/java/org/owasp/wrongsecrets/ChallengesControllerTest.java
index 24100f311..3407665a2 100644
--- a/src/test/java/org/owasp/wrongsecrets/ChallengesControllerTest.java
+++ b/src/test/java/org/owasp/wrongsecrets/ChallengesControllerTest.java
@@ -62,6 +62,16 @@ void shouldReturnSpoiler() throws Exception {
.andExpect(model().attribute("spoiler", new Spoiler("solution")));
}
+ @Test
+ void shouldReturnNotFound() throws Exception {
+ // when(challenge.solved(anyString())).thenReturn(false);
+ // when(challenge.supportedRuntimeEnvironments()).thenReturn(List.of(Environment.DOCKER));
+ this.mvc.perform(get("/challenge/-1"))
+ .andExpect(status().isNotFound());
+ this.mvc.perform(get("/challenge/99999999"))
+ .andExpect(status().isNotFound());
+ }
+
@Test
void shouldReturnIncorrectAnswerMessageWhenChallengeIsNotSolved() throws Exception {
when(challenge.solved(anyString())).thenReturn(false);
diff --git a/src/test/java/org/owasp/wrongsecrets/canaries/CanaryCallbackTest.java b/src/test/java/org/owasp/wrongsecrets/canaries/CanaryCallbackTest.java
index 054e732c7..4be9120ed 100644
--- a/src/test/java/org/owasp/wrongsecrets/canaries/CanaryCallbackTest.java
+++ b/src/test/java/org/owasp/wrongsecrets/canaries/CanaryCallbackTest.java
@@ -22,7 +22,7 @@ class CanaryCallbackTest {
@Test
void shouldAcceptPostOfMessage() {
var restTemplate = builder.build();
- var additonalCanaryData = new AdditionalCanaryData("soruce", "agent", "referer", "locatoin");
+ var additonalCanaryData = new AdditionalCanaryData("source", "agent", "referer", "location");
CanaryToken token = new CanaryToken("url", "memo", "channel", "time", additonalCanaryData);
var callbackAdress = "http://localhost:" + port + "/canaries/tokencallback";
@@ -37,5 +37,5 @@ void shouldAcceptPostOfMessage() {
}
/*
-"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "soruce", "useragent" : "agent", "referer" : "referer", "location" : "locatoin"}}
+"manageUrl" : "url", "memo" : "memo", "channel" : "channel", "time" : "time", "additionalData" : { "srcIp" : "source", "useragent" : "agent", "referer" : "referer", "location" : "location"}}
*/