From aa1c276deca6db0e209db5bc15b44c3579d17696 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme Date: Sun, 6 Sep 2026 22:36:23 +0530 Subject: [PATCH 01/19] feat(docker): introduce JDK 22 build container and challenge --- .devcontainer/devcontainer.json | 18 +++++++++++ .../docker/ChallengeBuildContainer.java | 27 ++++++++++++++++ .../challenge_build_container.html | 12 +++++++ .../docker/ChallengeBuildContainerTest.java | 31 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java create mode 100644 src/main/resources/explanations/challenge_build_container.html create mode 100644 src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..608edc0ee --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,18 @@ +{ + "name": "OWASP WrongSecrets Dev Container (JDK 22)", + "image": "eclipse-temurin:22-jdk-jammy", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/git:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "vscjava.vscode-java-pack", + "ms-azuretools.vscode-docker", + "redhat.vscode-yaml" + ] + } + }, + "remoteUser": "root" +} diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java new file mode 100644 index 000000000..ee0bd0efd --- /dev/null +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java @@ -0,0 +1,27 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import org.owasp.wrongsecrets.challenges.Challenge; +import org.owasp.wrongsecrets.challenges.Spoiler; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class ChallengeBuildContainer extends Challenge { + + private final String buildSecret; + + public ChallengeBuildContainer( + @Value("${build.container.secret:WSECR-build-layer-secret-849201}") String buildSecret) { + this.buildSecret = buildSecret; + } + + @Override + public boolean answerCorrect(String answer) { + return buildSecret != null && buildSecret.trim().equals(answer != null ? answer.trim() : ""); + } + + @Override + public Spoiler spoiler() { + return new Spoiler(buildSecret); + } +} diff --git a/src/main/resources/explanations/challenge_build_container.html b/src/main/resources/explanations/challenge_build_container.html new file mode 100644 index 000000000..7b9d0048d --- /dev/null +++ b/src/main/resources/explanations/challenge_build_container.html @@ -0,0 +1,12 @@ +
+

Challenge: Injected Build Container Secret

+

+ In multi-stage container builds, passing secrets with build arguments (ARG) + or intermediate build layers can persist in image history or intermediate artifacts. +

+

Remediation

+ +
diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java new file mode 100644 index 000000000..e661c305e --- /dev/null +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java @@ -0,0 +1,31 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +class ChallengeBuildContainerTest { + + private ChallengeBuildContainer challenge; + private final String expectedSecret = "WSECR-build-layer-secret-849201"; + + @BeforeEach + void setUp() { + challenge = new ChallengeBuildContainer(expectedSecret); + } + + @Test + void shouldAcceptCorrectBuildSecret() { + assertThat(challenge.answerCorrect(expectedSecret)).isTrue(); + } + + @Test + void shouldRejectIncorrectSecret() { + assertThat(challenge.answerCorrect("wrong-secret")).isFalse(); + } + + @Test + void shouldProvideCorrectSpoiler() { + assertThat(challenge.spoiler().solution()).isEqualTo(expectedSecret); + } +} From 3884ebd9fc66074491d6e311e9b1818636363985 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme Date: Mon, 7 Sep 2026 11:01:18 +0530 Subject: [PATCH 02/19] fix: resolve UTF-8 BOM and configure Java 26 devcontainer --- .devcontainer/devcontainer.json | 46 +++++++++++++++---- .../docker/ChallengeBuildContainer.java | 2 +- .../challenge_build_container.html | 2 +- .../docker/ChallengeBuildContainerTest.java | 2 +- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 608edc0ee..c4644f782 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,18 +1,48 @@ -{ - "name": "OWASP WrongSecrets Dev Container (JDK 22)", - "image": "eclipse-temurin:22-jdk-jammy", +{ + "name": "OWASP WrongSecrets (Java 26)", + "image": "eclipse-temurin:26-jdk-jammy", "features": { - "ghcr.io/devcontainers/features/docker-in-docker:2": {}, - "ghcr.io/devcontainers/features/git:1": {} + "ghcr.io/devcontainers/features/docker-in-docker:2": { + "enableOnStartup": true + }, + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": true, + "configureZshAsDefaultShell": true + } + }, + "forwardPorts": [8080, 8090], + "portsAttributes": { + "8080": { + "label": "WrongSecrets Web UI", + "onAutoForward": "notify" + }, + "8090": { + "label": "WrongSecrets Vault UI", + "onAutoForward": "silent" + } }, "customizations": { "vscode": { "extensions": [ "vscjava.vscode-java-pack", "ms-azuretools.vscode-docker", - "redhat.vscode-yaml" - ] + "redhat.vscode-yaml", + "redhat.vscode-xml", + "eamodio.gitlens" + ], + "settings": { + "java.configuration.runtimes": [ + { + "name": "JavaSE-26", + "path": "/opt/java/openjdk", + "default": true + } + ], + "java.compile.nullAnalysis.mode": "automatic" + } } }, + "postCreateCommand": "chmod +x ./mvnw && ./mvnw dependency:resolve", "remoteUser": "root" -} +} \ No newline at end of file diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java index ee0bd0efd..e3c81a07d 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java @@ -1,4 +1,4 @@ -package org.owasp.wrongsecrets.challenges.docker; +package org.owasp.wrongsecrets.challenges.docker; import org.owasp.wrongsecrets.challenges.Challenge; import org.owasp.wrongsecrets.challenges.Spoiler; diff --git a/src/main/resources/explanations/challenge_build_container.html b/src/main/resources/explanations/challenge_build_container.html index 7b9d0048d..f73314883 100644 --- a/src/main/resources/explanations/challenge_build_container.html +++ b/src/main/resources/explanations/challenge_build_container.html @@ -1,4 +1,4 @@ -
+

Challenge: Injected Build Container Secret

In multi-stage container builds, passing secrets with build arguments (ARG) diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java index e661c305e..eea40f232 100644 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java @@ -1,4 +1,4 @@ -package org.owasp.wrongsecrets.challenges.docker; +package org.owasp.wrongsecrets.challenges.docker; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 41a017f7e6bde15ad54e1d8515a025e056a31b7b Mon Sep 17 00:00:00 2001 From: sandeshkuldharme Date: Mon, 7 Sep 2026 11:18:27 +0530 Subject: [PATCH 03/19] fix(encoding): strip UTF-8 BOM from Java source files --- .../wrongsecrets/challenges/docker/ChallengeBuildContainer.java | 2 +- .../challenges/docker/ChallengeBuildContainerTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java index e3c81a07d..5e229c56d 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java @@ -24,4 +24,4 @@ public boolean answerCorrect(String answer) { public Spoiler spoiler() { return new Spoiler(buildSecret); } -} +} \ No newline at end of file diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java index eea40f232..4181b6ff1 100644 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java @@ -28,4 +28,4 @@ void shouldRejectIncorrectSecret() { void shouldProvideCorrectSpoiler() { assertThat(challenge.spoiler().solution()).isEqualTo(expectedSecret); } -} +} \ No newline at end of file From ad15ce84283b2973b329f75f3a809a19b577e4cf Mon Sep 17 00:00:00 2001 From: sandeshkuldharme Date: Mon, 7 Sep 2026 18:09:32 +0530 Subject: [PATCH 04/19] style: apply spotless formatting and add Javadoc --- .../docker/ChallengeBuildContainer.java | 29 +++++------ .../docker/ChallengeBuildContainerTest.java | 49 ++++++++++--------- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java index 5e229c56d..305a1af4f 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java @@ -5,23 +5,24 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +/** Challenge for finding secrets leaked in build container layers. */ @Component public class ChallengeBuildContainer extends Challenge { - private final String buildSecret; + private final String buildSecret; - public ChallengeBuildContainer( - @Value("${build.container.secret:WSECR-build-layer-secret-849201}") String buildSecret) { - this.buildSecret = buildSecret; - } + public ChallengeBuildContainer( + @Value("${build.container.secret:WSECR-build-layer-secret-849201}") String buildSecret) { + this.buildSecret = buildSecret; + } - @Override - public boolean answerCorrect(String answer) { - return buildSecret != null && buildSecret.trim().equals(answer != null ? answer.trim() : ""); - } + @Override + public boolean answerCorrect(String answer) { + return buildSecret != null && buildSecret.trim().equals(answer != null ? answer.trim() : ""); + } - @Override - public Spoiler spoiler() { - return new Spoiler(buildSecret); - } -} \ No newline at end of file + @Override + public Spoiler spoiler() { + return new Spoiler(buildSecret); + } +} diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java index 4181b6ff1..5fc653124 100644 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java @@ -1,31 +1,32 @@ package org.owasp.wrongsecrets.challenges.docker; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; class ChallengeBuildContainerTest { - private ChallengeBuildContainer challenge; - private final String expectedSecret = "WSECR-build-layer-secret-849201"; - - @BeforeEach - void setUp() { - challenge = new ChallengeBuildContainer(expectedSecret); - } - - @Test - void shouldAcceptCorrectBuildSecret() { - assertThat(challenge.answerCorrect(expectedSecret)).isTrue(); - } - - @Test - void shouldRejectIncorrectSecret() { - assertThat(challenge.answerCorrect("wrong-secret")).isFalse(); - } - - @Test - void shouldProvideCorrectSpoiler() { - assertThat(challenge.spoiler().solution()).isEqualTo(expectedSecret); - } -} \ No newline at end of file + private ChallengeBuildContainer challenge; + private final String expectedSecret = "WSECR-build-layer-secret-849201"; + + @BeforeEach + void setUp() { + challenge = new ChallengeBuildContainer(expectedSecret); + } + + @Test + void shouldAcceptCorrectBuildSecret() { + assertThat(challenge.answerCorrect(expectedSecret)).isTrue(); + } + + @Test + void shouldRejectIncorrectSecret() { + assertThat(challenge.answerCorrect("wrong-secret")).isFalse(); + } + + @Test + void shouldProvideCorrectSpoiler() { + assertThat(challenge.spoiler().solution()).isEqualTo(expectedSecret); + } +} From 63c3fa8ac83635340d03ce5ba53931bdd410feaf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:18:45 +0000 Subject: [PATCH 05/19] [pre-commit.ci lite] apply automatic fixes --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c4644f782..67f3f83ad 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -45,4 +45,4 @@ }, "postCreateCommand": "chmod +x ./mvnw && ./mvnw dependency:resolve", "remoteUser": "root" -} \ No newline at end of file +} From 42cd957f0b89c1488aedcb573a6ebf98dc71ae29 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme Date: Tue, 8 Sep 2026 15:17:27 +0530 Subject: [PATCH 06/19] feat: add Challenge 67 components and update contributing guide for dev containers --- CONTRIBUTING.md | 19 +++++++++++ ...geBuildContainer.java => Challenge67.java} | 21 ++++++------ .../resources/explanations/challenge67.adoc | 9 ++++++ .../explanations/challenge67_hint.adoc | 8 +++++ .../explanations/challenge67_reason.adoc | 7 ++++ .../challenge_build_container.html | 12 ------- .../wrong-secrets-configuration.yaml | 14 ++++++++ .../challenges/docker/Challenge67Test.java | 30 +++++++++++++++++ .../docker/ChallengeBuildContainerTest.java | 32 ------------------- 9 files changed, 97 insertions(+), 55 deletions(-) rename src/main/java/org/owasp/wrongsecrets/challenges/docker/{ChallengeBuildContainer.java => Challenge67.java} (50%) create mode 100644 src/main/resources/explanations/challenge67.adoc create mode 100644 src/main/resources/explanations/challenge67_hint.adoc create mode 100644 src/main/resources/explanations/challenge67_reason.adoc delete mode 100644 src/main/resources/explanations/challenge_build_container.html create mode 100644 src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java delete mode 100644 src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 415e305f6..c5ed100c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -165,6 +165,25 @@ Pull requests should be as small/atomic as possible. Large, wide-sweeping change ## How to set up your Contributor Environment +### Using Dev Containers + +Here is how you can use the Dev Container to build and run the entire application completely: + +#### 1. Open in Dev Container +- **In VS Code**: Press `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS) -> select **"Dev Containers: Reopen in Container"** (or click the green prompt in the bottom-left corner). +- **In GitHub Codespaces**: Select **Code** -> **Codespaces** -> **Create codespace on this branch**. + +*(The container will automatically set up Java, Docker-in-Docker, forwarded ports, and run the Maven setup).* + +#### 2. Build the Complete App +Inside the integrated Dev Container terminal, run: + +```bash +./mvnw clean install +``` + +### Manual Setup + 1. Create a GitHub account. Multiple different GitHub subscription plans are available, but you only need a free one. Follow [these steps](https://help.github.com/en/articles/signing-up-for-a-new-github-account "Signing up for a new GitHub account") to set up your account. 2. Fork the repository. Creating a fork means creating a copy of the repository on your own account, which you can modify without any impact on this repository. GitHub has an [article that describes all the needed steps](https://help.github.com/en/articles/fork-a-repo "Fork a repo"). 3. Clone your own repository to your host computer so that you can make modifications. If you followed the GitHub tutorial from step 2, you have already done this. diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java similarity index 50% rename from src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java rename to src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java index 305a1af4f..8d9c563f2 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainer.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java @@ -1,28 +1,27 @@ package org.owasp.wrongsecrets.challenges.docker; -import org.owasp.wrongsecrets.challenges.Challenge; -import org.owasp.wrongsecrets.challenges.Spoiler; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** Challenge for finding secrets leaked in build container layers. */ @Component -public class ChallengeBuildContainer extends Challenge { +public class Challenge67 extends FixedAnswerChallenge { private final String buildSecret; - public ChallengeBuildContainer( + /** + * Constructor for creating a new Challenge67 object. + * + * @param buildSecret The build container secret. + */ + public Challenge67( @Value("${build.container.secret:WSECR-build-layer-secret-849201}") String buildSecret) { this.buildSecret = buildSecret; } @Override - public boolean answerCorrect(String answer) { - return buildSecret != null && buildSecret.trim().equals(answer != null ? answer.trim() : ""); - } - - @Override - public Spoiler spoiler() { - return new Spoiler(buildSecret); + public String getAnswer() { + return this.buildSecret; } } diff --git a/src/main/resources/explanations/challenge67.adoc b/src/main/resources/explanations/challenge67.adoc new file mode 100644 index 000000000..7eae42eb6 --- /dev/null +++ b/src/main/resources/explanations/challenge67.adoc @@ -0,0 +1,9 @@ +=== Injected Build Container Secret + +In multi-stage container builds, passing secrets with build arguments (`ARG`) or intermediate build layers can persist in image history or intermediate artifacts. Can you inspect the container build layers to find the leaked build-time secret? + +To solve it: + +. Inspect the container image layers and build history using `docker history --no-trunc` or container inspection tools. +. Identify the build argument or layer where the secret was injected during build time. +. Submit the discovered secret in the input field below. diff --git a/src/main/resources/explanations/challenge67_hint.adoc b/src/main/resources/explanations/challenge67_hint.adoc new file mode 100644 index 000000000..db4297809 --- /dev/null +++ b/src/main/resources/explanations/challenge67_hint.adoc @@ -0,0 +1,8 @@ +You can solve this challenge by using: + +1. `docker history`: +- Run `docker history --no-trunc jeroenwillemsen/wrongsecrets:` to inspect the build arguments and instructions for each layer. +- Look for `ARG` or build-time environment configurations carrying secrets. + +2. Inspecting intermediate layers or using container analysis tools: +- Use tools like https://github.com/wagoodman/dive[dive] or https://github.com/goodwithtech/dockle[dockle] to analyze layer contents and discover build artifact remnants. diff --git a/src/main/resources/explanations/challenge67_reason.adoc b/src/main/resources/explanations/challenge67_reason.adoc new file mode 100644 index 000000000..f12e329b3 --- /dev/null +++ b/src/main/resources/explanations/challenge67_reason.adoc @@ -0,0 +1,7 @@ +*Why secrets in container build stages and build arguments are a security risk* + +Using `ARG` or plain files to pass secrets into multi-stage container builds often leaks sensitive data into the container image metadata or intermediate layer cache. Anyone with access to the container image can run `docker history` or inspect image layers to recover build-time credentials. + +*Remediation:* +- Use **Docker BuildKit Secret Mounts** (`--mount=type=secret`) which ensure secrets are only available during the specific build command and never written into any image layer. +- Never write raw credentials to build-time property files or build arguments. diff --git a/src/main/resources/explanations/challenge_build_container.html b/src/main/resources/explanations/challenge_build_container.html deleted file mode 100644 index f73314883..000000000 --- a/src/main/resources/explanations/challenge_build_container.html +++ /dev/null @@ -1,12 +0,0 @@ -

-

Challenge: Injected Build Container Secret

-

- In multi-stage container builds, passing secrets with build arguments (ARG) - or intermediate build layers can persist in image history or intermediate artifacts. -

-

Remediation

-
    -
  • Use Docker BuildKit Secret Mounts (--mount=type=secret).
  • -
  • Never write raw credentials to build-time property files.
  • -
-
diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index 9b88ec387..44f39b798 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -1014,6 +1014,19 @@ configurations: ctf: enabled: true + - name: Challenge 67 + short-name: "challenge-67" + sources: + - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge67" + explanation: "explanations/challenge67.adoc" + hint: "explanations/challenge67_hint.adoc" + reason: "explanations/challenge67_reason.adoc" + ui-snippet: "challenges/challenge-67/challenge-67.snippet" + environments: *all_envs + difficulty: *easy + category: *docker_tech + ctf: + enabled: true - name: Challenge 68 short-name: "challenge-68" sources: @@ -1040,6 +1053,7 @@ configurations: category: *ai ctf: enabled: true + - name: Challenge 70 short-name: "challenge-70" sources: diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java new file mode 100644 index 000000000..01a058ca5 --- /dev/null +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java @@ -0,0 +1,30 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.owasp.wrongsecrets.challenges.Spoiler; + +class Challenge67Test { + + @Test + void spoilerShouldRevealAnswer() { + var challenge = new Challenge67("test-secret"); + + assertThat(challenge.spoiler()).isEqualTo(new Spoiler("test-secret")); + } + + @Test + void rightAnswerShouldSolveChallenge() { + var challenge = new Challenge67("test-secret"); + + assertThat(challenge.answerCorrect("test-secret")).isTrue(); + } + + @Test + void incorrectAnswerShouldNotSolveChallenge() { + var challenge = new Challenge67("test-secret"); + + assertThat(challenge.answerCorrect("wrong answer")).isFalse(); + } +} diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java deleted file mode 100644 index 5fc653124..000000000 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/ChallengeBuildContainerTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.owasp.wrongsecrets.challenges.docker; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class ChallengeBuildContainerTest { - - private ChallengeBuildContainer challenge; - private final String expectedSecret = "WSECR-build-layer-secret-849201"; - - @BeforeEach - void setUp() { - challenge = new ChallengeBuildContainer(expectedSecret); - } - - @Test - void shouldAcceptCorrectBuildSecret() { - assertThat(challenge.answerCorrect(expectedSecret)).isTrue(); - } - - @Test - void shouldRejectIncorrectSecret() { - assertThat(challenge.answerCorrect("wrong-secret")).isFalse(); - } - - @Test - void shouldProvideCorrectSpoiler() { - assertThat(challenge.spoiler().solution()).isEqualTo(expectedSecret); - } -} From b1d7a93bb13c205cd409fe70fa88a996c24151e4 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme Date: Wed, 9 Sep 2026 11:54:27 +0530 Subject: [PATCH 07/19] feat: refactor Challenge 67 to Dev Container secret leak and add complete devcontainer dependencies --- .devcontainer/devcontainer.json | 24 +++++++++++++-- CONTRIBUTING.md | 29 ++++++++++++++----- .../challenges/docker/Challenge67.java | 12 ++++---- .../challenge-67/challenge-67.snippet | 20 +++++++++++++ .../resources/explanations/challenge67.adoc | 12 ++++---- .../explanations/challenge67_hint.adoc | 14 +++++---- .../explanations/challenge67_reason.adoc | 19 ++++++++---- .../wrong-secrets-configuration.yaml | 1 + .../challenges/docker/Challenge67Test.java | 14 +++++---- 9 files changed, 107 insertions(+), 38 deletions(-) create mode 100644 src/main/resources/challenges/challenge-67/challenge-67.snippet diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 67f3f83ad..264a1379e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,18 @@ { - "name": "OWASP WrongSecrets (Java 26)", + "name": "OWASP WrongSecrets (Java 26 & Node.js 26 Dev Container)", "image": "eclipse-temurin:26-jdk-jammy", "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "26" + }, + "ghcr.io/devcontainers/features/python:1": { + "version": "3.12" + }, + "ghcr.io/devcontainers/features/terraform:1": { + "version": "latest", + "tflint": "latest" + }, + "ghcr.io/devcontainers-contrib/features/terraform-docs:1": {}, "ghcr.io/devcontainers/features/docker-in-docker:2": { "enableOnStartup": true }, @@ -11,6 +22,9 @@ "configureZshAsDefaultShell": true } }, + "containerEnv": { + "DEVCONTAINER_SECRET": "WSECR-devcontainer-token-774921" + }, "forwardPorts": [8080, 8090], "portsAttributes": { "8080": { @@ -29,7 +43,11 @@ "ms-azuretools.vscode-docker", "redhat.vscode-yaml", "redhat.vscode-xml", - "eamodio.gitlens" + "eamodio.gitlens", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "asciidoctor.asciidoctor-vscode", + "hashicorp.terraform" ], "settings": { "java.configuration.runtimes": [ @@ -43,6 +61,6 @@ } } }, - "postCreateCommand": "chmod +x ./mvnw && ./mvnw dependency:resolve", + "postCreateCommand": "chmod +x ./mvnw && ./mvnw dependency:resolve -DskipTests && npm install && pip install pre-commit && pre-commit install && pre-commit install --hook-type commit-msg", "remoteUser": "root" } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c5ed100c6..7fbdce32c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -165,21 +165,36 @@ Pull requests should be as small/atomic as possible. Large, wide-sweeping change ## How to set up your Contributor Environment -### Using Dev Containers +### Using Dev Containers (Zero Local Dependencies) -Here is how you can use the Dev Container to build and run the entire application completely: +The project includes a fully configured Dev Container for **VS Code** and **GitHub Codespaces**. You do not need to install Java, Maven, Node.js, Python, or Terraform tools locally on your machine—everything is self-contained inside the Dev Container. + +The Dev Container environment automatically provides: +- **JDK 26** & **Maven Wrapper** (`./mvnw`) +- **Node.js 26** & **npm** (for commitlint, ESLint, and frontend build) +- **Python 3** & **pre-commit** hooks +- **Terraform**, **tflint**, and **terraform-docs** (for pre-commit validation) +- **Docker-in-Docker** (for running Docker-based challenge environments) +- Pre-configured VS Code extensions and settings #### 1. Open in Dev Container -- **In VS Code**: Press `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS) -> select **"Dev Containers: Reopen in Container"** (or click the green prompt in the bottom-left corner). +- **In VS Code**: Press `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS) -> select **"Dev Containers: Reopen in Container"** (or click the prompt in the bottom-left corner). - **In GitHub Codespaces**: Select **Code** -> **Codespaces** -> **Create codespace on this branch**. -*(The container will automatically set up Java, Docker-in-Docker, forwarded ports, and run the Maven setup).* +*(The container automatically installs all dependencies, configures pre-commit hooks, and runs dependency resolution on launch).* -#### 2. Build the Complete App -Inside the integrated Dev Container terminal, run: +#### 2. Build and Test the Application +Inside the Dev Container integrated terminal, run: ```bash -./mvnw clean install +# Compile and run tests +./mvnw clean compile test + +# Start the application +./mvnw spring-boot:run + +# Run pre-commit checks across all files +pre-commit run --all-files ``` ### Manual Setup diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java index 8d9c563f2..b5d7c34ef 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java @@ -4,24 +4,24 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -/** Challenge for finding secrets leaked in build container layers. */ +/** Challenge for finding secrets leaked in Dev Container configurations and environments. */ @Component public class Challenge67 extends FixedAnswerChallenge { - private final String buildSecret; + private final String devcontainerSecret; /** * Constructor for creating a new Challenge67 object. * - * @param buildSecret The build container secret. + * @param devcontainerSecret The secret configured in the Dev Container environment. */ public Challenge67( - @Value("${build.container.secret:WSECR-build-layer-secret-849201}") String buildSecret) { - this.buildSecret = buildSecret; + @Value("${DEVCONTAINER_SECRET:WSECR-devcontainer-token-774921}") String devcontainerSecret) { + this.devcontainerSecret = devcontainerSecret; } @Override public String getAnswer() { - return this.buildSecret; + return this.devcontainerSecret; } } diff --git a/src/main/resources/challenges/challenge-67/challenge-67.snippet b/src/main/resources/challenges/challenge-67/challenge-67.snippet new file mode 100644 index 000000000..3fe81c7a1 --- /dev/null +++ b/src/main/resources/challenges/challenge-67/challenge-67.snippet @@ -0,0 +1,20 @@ +
+

🐳 Dev Container Configuration Inspector

+

Development containers allow teams to share reproducible development environments. However, committing hardcoded environment variables or secrets into .devcontainer/devcontainer.json can expose sensitive credentials to anyone with repository access.

+ +
+ // .devcontainer/devcontainer.json excerpt
+ {
+   "name": "OWASP WrongSecrets (Java 26 & Node.js 26 Dev Container)",
+   "image": "eclipse-temurin:26-jdk-jammy",
+   "containerEnv": {
+     "DEVCONTAINER_SECRET": "WSECR-devcontainer-token-774921"
+   },
+   "postCreateCommand": "chmod +x ./mvnw && ./mvnw dependency:resolve -DskipTests && npm install && pip install pre-commit && pre-commit install"
+ } +
+ +
+ 💡 Tip: Check the DEVCONTAINER_SECRET environment variable defined in the Dev Container configuration. +
+
diff --git a/src/main/resources/explanations/challenge67.adoc b/src/main/resources/explanations/challenge67.adoc index 7eae42eb6..ac05004e6 100644 --- a/src/main/resources/explanations/challenge67.adoc +++ b/src/main/resources/explanations/challenge67.adoc @@ -1,9 +1,11 @@ -=== Injected Build Container Secret +=== Dev Container Secret Leak -In multi-stage container builds, passing secrets with build arguments (`ARG`) or intermediate build layers can persist in image history or intermediate artifacts. Can you inspect the container build layers to find the leaked build-time secret? +Development containers (Dev Containers) allow teams to define reproducible development environments using containerization tools like VS Code Remote - Containers and GitHub Codespaces. By encapsulating tools, runtimes, and dependencies within `.devcontainer/devcontainer.json`, developers can get started without installing complex local software stacks. -To solve it: +However, developers frequently make the mistake of embedding sensitive tokens, passwords, API keys, or private registry access credentials directly into `.devcontainer/devcontainer.json` (such as in `containerEnv`, `remoteEnv`, or lifecycle scripts) and committing them to version control. -. Inspect the container image layers and build history using `docker history --no-trunc` or container inspection tools. -. Identify the build argument or layer where the secret was injected during build time. +To solve this challenge: + +. Inspect the `.devcontainer/devcontainer.json` configuration file in the project repository or review the configuration snippet in the UI. +. Identify the leaked `DEVCONTAINER_SECRET` or token defined in the container environment. . Submit the discovered secret in the input field below. diff --git a/src/main/resources/explanations/challenge67_hint.adoc b/src/main/resources/explanations/challenge67_hint.adoc index db4297809..4a89c8cd9 100644 --- a/src/main/resources/explanations/challenge67_hint.adoc +++ b/src/main/resources/explanations/challenge67_hint.adoc @@ -1,8 +1,10 @@ -You can solve this challenge by using: +You can solve this challenge using the following steps: -1. `docker history`: -- Run `docker history --no-trunc jeroenwillemsen/wrongsecrets:` to inspect the build arguments and instructions for each layer. -- Look for `ARG` or build-time environment configurations carrying secrets. +1. Inspect the Dev Container configuration file: +- Open the `.devcontainer/devcontainer.json` file in the root of the repository. +- Look for the `containerEnv` or `remoteEnv` sections where environment variables are defined. -2. Inspecting intermediate layers or using container analysis tools: -- Use tools like https://github.com/wagoodman/dive[dive] or https://github.com/goodwithtech/dockle[dockle] to analyze layer contents and discover build artifact remnants. +2. Inspect the running container environment: +- If running inside a dev container or Docker container, check the environment variables with `printenv DEVCONTAINER_SECRET` or `echo $DEVCONTAINER_SECRET`. + +3. Review the UI snippet provided on this challenge page for the exposed configuration. diff --git a/src/main/resources/explanations/challenge67_reason.adoc b/src/main/resources/explanations/challenge67_reason.adoc index f12e329b3..5b287c2e9 100644 --- a/src/main/resources/explanations/challenge67_reason.adoc +++ b/src/main/resources/explanations/challenge67_reason.adoc @@ -1,7 +1,16 @@ -*Why secrets in container build stages and build arguments are a security risk* += Dev Container Configuration Secret Exposure -Using `ARG` or plain files to pass secrets into multi-stage container builds often leaks sensitive data into the container image metadata or intermediate layer cache. Anyone with access to the container image can run `docker history` or inspect image layers to recover build-time credentials. +*Why Hardcoding Secrets in Dev Containers is a Critical Security Risk* -*Remediation:* -- Use **Docker BuildKit Secret Mounts** (`--mount=type=secret`) which ensure secrets are only available during the specific build command and never written into any image layer. -- Never write raw credentials to build-time property files or build arguments. +Dev Containers are shared development environments configured via `.devcontainer/devcontainer.json`. Because these files are typically tracked in version control, hardcoding secrets into devcontainer definitions presents several security dangers: + +1. **Exposure to All Repository Readers**: Anyone with read access to the source repository (or public forks and clones in open-source projects) can read secrets hardcoded in `.devcontainer/devcontainer.json`. +2. **Environment Variable Leakage**: Credentials defined in `containerEnv` or `remoteEnv` are injected into every process inside the container, making them accessible to any script, child process, or diagnostic tool running in the container. +3. **Persistent in Git History**: Once committed, removing the secret requires git history rewrites, and stale keys often remain valid indefinitely if rotation is not performed. + +*Remediation and Best Practices:* + +- **Use GitHub Codespaces Secrets / VS Code Dev Container Secrets**: Inject secrets dynamically via Codespaces repository/user secrets or VS Code settings rather than hardcoding them in configuration files. +- **Use Local Environment Substitution**: Reference host environment variables dynamically in `devcontainer.json` using `${localEnv:MY_SECRET}` syntax. +- **Use `.env` files with `.gitignore`**: Place development secrets in local `.env` files that are explicitly excluded from version control in `.gitignore`. +- **Adopt Secret Management Solutions**: Fetch secrets at runtime using dedicated secret managers (e.g., HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager). diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index 44f39b798..e8e833eea 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -1027,6 +1027,7 @@ configurations: category: *docker_tech ctf: enabled: true + - name: Challenge 68 short-name: "challenge-68" sources: diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java index 01a058ca5..240be4032 100644 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java @@ -7,24 +7,26 @@ class Challenge67Test { + private static final String DEFAULT_SECRET = "WSECR-devcontainer-token-774921"; + @Test void spoilerShouldRevealAnswer() { - var challenge = new Challenge67("test-secret"); + var challenge = new Challenge67(DEFAULT_SECRET); - assertThat(challenge.spoiler()).isEqualTo(new Spoiler("test-secret")); + assertThat(challenge.spoiler()).isEqualTo(new Spoiler(DEFAULT_SECRET)); } @Test void rightAnswerShouldSolveChallenge() { - var challenge = new Challenge67("test-secret"); + var challenge = new Challenge67(DEFAULT_SECRET); - assertThat(challenge.answerCorrect("test-secret")).isTrue(); + assertThat(challenge.answerCorrect(DEFAULT_SECRET)).isTrue(); } @Test void incorrectAnswerShouldNotSolveChallenge() { - var challenge = new Challenge67("test-secret"); + var challenge = new Challenge67(DEFAULT_SECRET); - assertThat(challenge.answerCorrect("wrong answer")).isFalse(); + assertThat(challenge.answerCorrect("wrong-secret-token")).isFalse(); } } From c612007574bc10eedf34b610af83063eef7a47cb Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Wed, 9 Sep 2026 16:52:45 +0530 Subject: [PATCH 08/19] Update pr-preview.yml --- .github/workflows/pr-preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index 01ac11b13..fa5e60a69 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -92,7 +92,7 @@ jobs: uses: docker/build-push-action@v6 with: context: . - push: true + push: false platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 873afba5dc741eb51153460da481b252cab39129 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Wed, 9 Sep 2026 16:59:21 +0530 Subject: [PATCH 09/19] fix(ci): add permissions for pages preview deployment --- .github/workflows/github-pages-preview.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/github-pages-preview.yml b/.github/workflows/github-pages-preview.yml index 2309c0063..3fbbe8f40 100644 --- a/.github/workflows/github-pages-preview.yml +++ b/.github/workflows/github-pages-preview.yml @@ -13,8 +13,8 @@ permissions: pages: write id-token: write pull-requests: write - -# Allow only one concurrent deployment per PR, but allow multiple PRs to deploy simultaneously + +# Allow only one concurrent deployment per PR, but allow multiple PRs to deploy concurrency: group: "pages-pr-${{ github.event.number }}" cancel-in-progress: true @@ -22,7 +22,6 @@ concurrency: env: NVD_API_KEY: ${{ secrets.NVD_API_KEY }} - jobs: generate-static-preview: runs-on: ubuntu-latest From f7c154e8e2158b961c678b1576a14fc918b9c982 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Wed, 9 Sep 2026 21:28:28 +0530 Subject: [PATCH 10/19] Update .github/workflows/pr-preview.yml Co-authored-by: Jeroen Willemsen --- .github/workflows/pr-preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index fa5e60a69..01ac11b13 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -92,7 +92,7 @@ jobs: uses: docker/build-push-action@v6 with: context: . - push: false + push: true platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From f7b049182dfc40d42d0fb93a4114a3f443caa605 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Wed, 9 Sep 2026 22:02:36 +0530 Subject: [PATCH 11/19] Update wrong-secrets-configuration.yaml --- .../wrong-secrets-configuration.yaml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index e8e833eea..0c07edd92 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -1014,20 +1014,7 @@ configurations: ctf: enabled: true - - name: Challenge 67 - short-name: "challenge-67" - sources: - - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge67" - explanation: "explanations/challenge67.adoc" - hint: "explanations/challenge67_hint.adoc" - reason: "explanations/challenge67_reason.adoc" - ui-snippet: "challenges/challenge-67/challenge-67.snippet" - environments: *all_envs - difficulty: *easy - category: *docker_tech - ctf: - enabled: true - + - name: Challenge 68 short-name: "challenge-68" sources: @@ -1068,3 +1055,16 @@ configurations: category: *ai ctf: enabled: true + - name: Challenge 71 + short-name: "challenge-71" + sources: + - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge71" + explanation: "explanations/challenge71.adoc" + hint: "explanations/challenge71_hint.adoc" + reason: "explanations/challenge71_reason.adoc" + ui-snippet: "challenges/challenge-71/challenge-71.snippet" + environments: *all_envs + difficulty: *easy + category: *docker_tech + ctf: + enabled: true From 7a8273235d4c0774394355029898b978cfd3ce69 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Wed, 9 Sep 2026 22:03:27 +0530 Subject: [PATCH 12/19] Update Challenge71.java --- .../org/owasp/wrongsecrets/challenges/docker/Challenge67.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java index b5d7c34ef..c8c05ea64 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java @@ -6,7 +6,7 @@ /** Challenge for finding secrets leaked in Dev Container configurations and environments. */ @Component -public class Challenge67 extends FixedAnswerChallenge { +public class Challenge71 extends FixedAnswerChallenge { private final String devcontainerSecret; @@ -15,7 +15,7 @@ public class Challenge67 extends FixedAnswerChallenge { * * @param devcontainerSecret The secret configured in the Dev Container environment. */ - public Challenge67( + public Challenge71( @Value("${DEVCONTAINER_SECRET:WSECR-devcontainer-token-774921}") String devcontainerSecret) { this.devcontainerSecret = devcontainerSecret; } From 66018a01e5a87d02577e4f41f472106ab2adf625 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Wed, 9 Sep 2026 22:05:33 +0530 Subject: [PATCH 13/19] Update Challenge71Test.java --- .../owasp/wrongsecrets/challenges/docker/Challenge67Test.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java index 240be4032..f47c93519 100644 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; import org.owasp.wrongsecrets.challenges.Spoiler; -class Challenge67Test { +class Challenge71Test { private static final String DEFAULT_SECRET = "WSECR-devcontainer-token-774921"; @@ -18,7 +18,7 @@ void spoilerShouldRevealAnswer() { @Test void rightAnswerShouldSolveChallenge() { - var challenge = new Challenge67(DEFAULT_SECRET); + var challenge = new Challenge71(DEFAULT_SECRET); assertThat(challenge.answerCorrect(DEFAULT_SECRET)).isTrue(); } From bf5e4934e14ea6aa7a05c6dc534ce9496973d415 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Wed, 9 Sep 2026 22:06:08 +0530 Subject: [PATCH 14/19] Rename Challenge67Test.java to Challenge71Test.java --- .../docker/{Challenge67Test.java => Challenge71Test.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/java/org/owasp/wrongsecrets/challenges/docker/{Challenge67Test.java => Challenge71Test.java} (100%) diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge71Test.java similarity index 100% rename from src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge67Test.java rename to src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge71Test.java From 300cfb9cec4844dc458057ba656eb539ec8dc7f1 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Wed, 9 Sep 2026 22:06:40 +0530 Subject: [PATCH 15/19] Rename Challenge67.java to Challenge71.java --- .../challenges/docker/{Challenge67.java => Challenge71.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/owasp/wrongsecrets/challenges/docker/{Challenge67.java => Challenge71.java} (100%) diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge71.java similarity index 100% rename from src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge67.java rename to src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge71.java From c61612d09ef97779d485bbeb2056eebd5cb82d1b Mon Sep 17 00:00:00 2001 From: sandeshkuldharme Date: Thu, 10 Sep 2026 00:08:19 +0530 Subject: [PATCH 16/19] fix(challenge71): fix Challenge71Test references, yaml syntax, and rename resource files --- .github/workflows/github-pages-preview.yml | 2 +- .../owasp/wrongsecrets/challenges/docker/Challenge71.java | 2 +- .../challenge-71.snippet} | 0 .../explanations/{challenge67.adoc => challenge71.adoc} | 0 .../{challenge67_hint.adoc => challenge71_hint.adoc} | 0 .../{challenge67_reason.adoc => challenge71_reason.adoc} | 0 src/main/resources/wrong-secrets-configuration.yaml | 5 +++-- .../wrongsecrets/challenges/docker/Challenge71Test.java | 4 ++-- 8 files changed, 7 insertions(+), 6 deletions(-) rename src/main/resources/challenges/{challenge-67/challenge-67.snippet => challenge-71/challenge-71.snippet} (100%) rename src/main/resources/explanations/{challenge67.adoc => challenge71.adoc} (100%) rename src/main/resources/explanations/{challenge67_hint.adoc => challenge71_hint.adoc} (100%) rename src/main/resources/explanations/{challenge67_reason.adoc => challenge71_reason.adoc} (100%) diff --git a/.github/workflows/github-pages-preview.yml b/.github/workflows/github-pages-preview.yml index 3fbbe8f40..df7bd9945 100644 --- a/.github/workflows/github-pages-preview.yml +++ b/.github/workflows/github-pages-preview.yml @@ -13,7 +13,7 @@ permissions: pages: write id-token: write pull-requests: write - + # Allow only one concurrent deployment per PR, but allow multiple PRs to deploy concurrency: group: "pages-pr-${{ github.event.number }}" diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge71.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge71.java index c8c05ea64..9673bbc2b 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge71.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge71.java @@ -11,7 +11,7 @@ public class Challenge71 extends FixedAnswerChallenge { private final String devcontainerSecret; /** - * Constructor for creating a new Challenge67 object. + * Constructor for creating a new Challenge71 object. * * @param devcontainerSecret The secret configured in the Dev Container environment. */ diff --git a/src/main/resources/challenges/challenge-67/challenge-67.snippet b/src/main/resources/challenges/challenge-71/challenge-71.snippet similarity index 100% rename from src/main/resources/challenges/challenge-67/challenge-67.snippet rename to src/main/resources/challenges/challenge-71/challenge-71.snippet diff --git a/src/main/resources/explanations/challenge67.adoc b/src/main/resources/explanations/challenge71.adoc similarity index 100% rename from src/main/resources/explanations/challenge67.adoc rename to src/main/resources/explanations/challenge71.adoc diff --git a/src/main/resources/explanations/challenge67_hint.adoc b/src/main/resources/explanations/challenge71_hint.adoc similarity index 100% rename from src/main/resources/explanations/challenge67_hint.adoc rename to src/main/resources/explanations/challenge71_hint.adoc diff --git a/src/main/resources/explanations/challenge67_reason.adoc b/src/main/resources/explanations/challenge71_reason.adoc similarity index 100% rename from src/main/resources/explanations/challenge67_reason.adoc rename to src/main/resources/explanations/challenge71_reason.adoc diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index 0c07edd92..ce5765249 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -1014,7 +1014,6 @@ configurations: ctf: enabled: true - - name: Challenge 68 short-name: "challenge-68" sources: @@ -1055,7 +1054,8 @@ configurations: category: *ai ctf: enabled: true - - name: Challenge 71 + + - name: Challenge 71 short-name: "challenge-71" sources: - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge71" @@ -1068,3 +1068,4 @@ configurations: category: *docker_tech ctf: enabled: true + diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge71Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge71Test.java index f47c93519..ca9fbae31 100644 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge71Test.java +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge71Test.java @@ -11,7 +11,7 @@ class Challenge71Test { @Test void spoilerShouldRevealAnswer() { - var challenge = new Challenge67(DEFAULT_SECRET); + var challenge = new Challenge71(DEFAULT_SECRET); assertThat(challenge.spoiler()).isEqualTo(new Spoiler(DEFAULT_SECRET)); } @@ -25,7 +25,7 @@ void rightAnswerShouldSolveChallenge() { @Test void incorrectAnswerShouldNotSolveChallenge() { - var challenge = new Challenge67(DEFAULT_SECRET); + var challenge = new Challenge71(DEFAULT_SECRET); assertThat(challenge.answerCorrect("wrong-secret-token")).isFalse(); } From e1356f04894aaf40d94d10e73ef47d07d346a0eb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2026 20:40:05 +0000 Subject: [PATCH 17/19] [pre-commit.ci lite] apply automatic fixes --- src/main/resources/wrong-secrets-configuration.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index ce5765249..1c7eff993 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -1068,4 +1068,3 @@ configurations: category: *docker_tech ctf: enabled: true - From 6d9a6388ca6ce3c0f9fa125ecafe95af242f2854 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Thu, 10 Sep 2026 02:34:11 +0530 Subject: [PATCH 18/19] Update github-pages-preview.yml --- .github/workflows/github-pages-preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-pages-preview.yml b/.github/workflows/github-pages-preview.yml index df7bd9945..2c689cf4c 100644 --- a/.github/workflows/github-pages-preview.yml +++ b/.github/workflows/github-pages-preview.yml @@ -25,7 +25,7 @@ env: jobs: generate-static-preview: runs-on: ubuntu-latest - if: github.event.action != 'closed' + if: github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }}pr-${{ github.event.number }}/ From 6848093c216cac274c1091a7ba3fef5a20e801e2 Mon Sep 17 00:00:00 2001 From: sandeshkuldharme1 Date: Thu, 10 Sep 2026 02:34:51 +0530 Subject: [PATCH 19/19] Update pr-preview.yml --- .github/workflows/pr-preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index 01ac11b13..5b567570b 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -20,7 +20,7 @@ env: jobs: build-preview: runs-on: ubuntu-latest - if: github.event.action != 'closed' + if: github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository outputs: image-tag: ${{ steps.meta.outputs.tags }} image-digest: ${{ steps.build.outputs.digest }}