From bcc5724e7ddcc7aa641103e8451e38fcf09f4fde Mon Sep 17 00:00:00 2001 From: kekubhai Date: Tue, 22 Sep 2026 11:55:04 +0530 Subject: [PATCH 1/6] Add Challenge 73: Expose Secret in Agent Instruction Files - Introduced Challenge 73, which focuses on identifying a leaked secret in agent instruction files included in the dev container. - Updated Dockerfile to copy new agent context files into the container. - Added documentation for the challenge in AGENTS.md, CLAUDE.md, and new explanation files. - Updated README to reflect the total number of challenges. - Implemented tests to validate the challenge functionality and ensure correct token extraction from context files. --- .devcontainer/.cursor/rules/project.mdc | 17 ++++ .devcontainer/.windsurfrules | 8 ++ .devcontainer/AGENTS.md | 38 +++++++++ .devcontainer/CLAUDE.md | 34 ++++++++ Dockerfile | 3 + README.md | 3 +- .../challenges/docker/Challenge73.java | 64 +++++++++++++++ src/main/resources/application.properties | 1 + .../resources/explanations/challenge73.adoc | 25 ++++++ .../explanations/challenge73_hint.adoc | 15 ++++ .../explanations/challenge73_reason.adoc | 39 ++++++++++ .../wrong-secrets-configuration.yaml | 13 ++++ .../docker/Challenge73RegistrationTest.java | 36 +++++++++ .../challenges/docker/Challenge73Test.java | 78 +++++++++++++++++++ 14 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/.cursor/rules/project.mdc create mode 100644 .devcontainer/.windsurfrules create mode 100644 .devcontainer/AGENTS.md create mode 100644 .devcontainer/CLAUDE.md create mode 100644 src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge73.java create mode 100644 src/main/resources/explanations/challenge73.adoc create mode 100644 src/main/resources/explanations/challenge73_hint.adoc create mode 100644 src/main/resources/explanations/challenge73_reason.adoc create mode 100644 src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73RegistrationTest.java create mode 100644 src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73Test.java diff --git a/.devcontainer/.cursor/rules/project.mdc b/.devcontainer/.cursor/rules/project.mdc new file mode 100644 index 000000000..71968c801 --- /dev/null +++ b/.devcontainer/.cursor/rules/project.mdc @@ -0,0 +1,17 @@ +--- +description: Project rules for the WrongSecrets dev container +globs: ["**/*.java", "**/*.yaml", "**/*.adoc"] +alwaysApply: true +--- + +# WrongSecrets project rules + +- Challenge classes live in + `org.owasp.wrongsecrets.challenges.` (docker, kubernetes, cloud). +- Register every new challenge in + `src/main/resources/wrong-secrets-configuration.yaml`. +- Add `challengeNN.adoc`, `challengeNN_hint.adoc` and `challengeNN_reason.adoc` + under `src/main/resources/explanations/`. +- Keep the deliberately vulnerable behaviour: never remove a leaked secret. +- Reuse the shared staging credentials documented in `CLAUDE.md` instead of + creating new ones, and follow the repository conventions in `AGENTS.md`. diff --git a/.devcontainer/.windsurfrules b/.devcontainer/.windsurfrules new file mode 100644 index 000000000..33b84cf73 --- /dev/null +++ b/.devcontainer/.windsurfrules @@ -0,0 +1,8 @@ +# Windsurf rules + +- Use the Java 26 toolchain that ships with the dev container. +- Run `./mvnw test -Dtest=ChallengeNNTest` for the challenge you touched. +- Follow the challenge conventions documented in `AGENTS.md`. +- Do not commit real credentials. The staging deploy helper expects the shared + token that is kept in `CLAUDE.md`; import it rather than hardcoding your own. +- Keep explanation, hint and reason files in sync with the challenge class. diff --git a/.devcontainer/AGENTS.md b/.devcontainer/AGENTS.md new file mode 100644 index 000000000..5e9e95b7a --- /dev/null +++ b/.devcontainer/AGENTS.md @@ -0,0 +1,38 @@ +# AGENTS.md + +Context for automated coding agents working inside the WrongSecrets dev +container. + +## What this project is + +WrongSecrets is a deliberately vulnerable application that teaches secrets +management. Every challenge hides a secret in a realistic but insecure place. +Never "fix" a challenge by removing the secret or the surrounding weakness: the +insecure behaviour is the point. + +## Dev container + +- The repository is mounted at `/workspaces`. +- Start the application with `./mvnw spring-boot:run` (it listens on `8080`). +- Run the tests with `./mvnw test`, or a single test with + `./mvnw test -Dtest=Challenge73Test`. +- Java, Maven, Node.js, Go, Terraform and the Docker CLI are already installed. + Do not install system packages unless a task explicitly requires it. + +## Conventions + +- Java sources live under `src/main/java/org/owasp/wrongsecrets/`. +- Every challenge needs a class, an entry in + `src/main/resources/wrong-secrets-configuration.yaml`, and explanation, hint + and reason files under `src/main/resources/explanations/`. +- Format Java with `./mvnw spotless:apply` and keep the existing + google-java-format style. +- Tests use JUnit 5 and AssertJ. + +## Credentials + +- Real credentials must never be committed. Read them from the environment, for + example `export STAGING_DEPLOY_TOKEN=...` in your own shell. +- The shared staging token used by the local deploy helper is documented in + `CLAUDE.md` so that every agent reuses the same value instead of inventing a + new one. See also `.cursor/rules/project.mdc` and `.windsurfrules`. diff --git a/.devcontainer/CLAUDE.md b/.devcontainer/CLAUDE.md new file mode 100644 index 000000000..d9cedefc2 --- /dev/null +++ b/.devcontainer/CLAUDE.md @@ -0,0 +1,34 @@ +# CLAUDE.md + +Guidance for Claude Code when working in this repository. The file is shipped +with the dev container so that every agent starts with the same context. + +## Working agreements + +- Prefer small, focused changes and keep the existing package layout. +- Run `./mvnw spotless:apply` before committing. +- Ask before adding a new dependency. +- Do not weaken a challenge: the leaked secret is the exercise. + +## Build and test + +```bash +./mvnw spring-boot:run # start the app on http://localhost:8080 +./mvnw test # run the unit tests +./mvnw test -Dtest=Challenge73Test # run a single test +``` + +## Staging deploy helper + +The `deploy-preview` helper authenticates against the staging environment with +the shared team token. Looking it up in the password manager for every session +slowed the agent down, so paste it into your shell once per session: + +```bash +export STAGING_DEPLOY_URL="https://staging.wrongsecrets.example.com/api/v1/deploy" +export STAGING_DEPLOY_TOKEN="Ag3nt_C0nt3xt_L3ak3d_T0k3n!" +``` + +Never echo the token into logs or commit it into a script. Repository-wide rules +are duplicated for Cursor (`.cursor/rules/project.mdc`) and Windsurf +(`.windsurfrules`). diff --git a/Dockerfile b/Dockerfile index 203f63a9f..38e47cc92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,6 +54,9 @@ COPY --chown=wrongsecrets src/test/resources/RSAprivatekey.pem /var/tmp/helpers/ COPY --chown=wrongsecrets .ssh/ /home/wrongsecrets/.ssh/ COPY cursor/rules/project-specification.mdc /var/helpers/project-specification.mdc ENV PROJECT_SPEC_PATH=/var/helpers/project-specification.mdc +ENV AGENT_CONTEXT_PATH=/var/helpers/agent-context +COPY --chown=wrongsecrets .devcontainer/AGENTS.md .devcontainer/CLAUDE.md .devcontainer/.windsurfrules /var/helpers/agent-context/ +COPY --chown=wrongsecrets .devcontainer/.cursor /var/helpers/agent-context/.cursor COPY --from=builder /builder/extracted/dependencies/ ./ COPY --from=builder /builder/extracted/spring-boot-loader/ ./ diff --git a/README.md b/README.md index 88f6852cc..e96f5a9bb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Welcome to the OWASP WrongSecrets game! The game is packed with real life examples of how to _not_ store secrets in your software. Each of these examples is captured in a challenge, which you need to solve using various tools and techniques. Solving these challenges will help you recognize common mistakes & can help you to reflect on your own secrets management strategy. -Can you solve all the 72 challenges? +Can you solve all the 73 challenges? Try some of them on [our Heroku demo environment](https://wrongsecrets.herokuapp.com/). @@ -231,6 +231,7 @@ Now you can try to find the secrets by means of solving the challenge offered at - [localhost:8080/challenge/challenge-70](http://localhost:8080/challenge/challenge-70) - [localhost:8080/challenge/challenge-71](http://localhost:8080/challenge/challenge-71) - [localhost:8080/challenge/challenge-72](http://localhost:8080/challenge/challenge-72) +- [localhost:8080/challenge/challenge-73](http://localhost:8080/challenge/challenge-73) Note that these challenges are still very basic, and so are their explanations. Feel free to file a PR to make them look diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge73.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge73.java new file mode 100644 index 000000000..0ee9dc340 --- /dev/null +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge73.java @@ -0,0 +1,64 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import static org.owasp.wrongsecrets.Challenges.ErrorResponses.FILE_MOUNT_ERROR; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.regex.Pattern; +import lombok.extern.slf4j.Slf4j; +import org.owasp.wrongsecrets.challenges.FixedAnswerChallenge; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Challenge about secrets that are committed to AI agent instruction/context files. The dev + * container ships {@code AGENTS.md}, {@code CLAUDE.md}, {@code .cursor/rules/project.mdc} and + * {@code .windsurfrules}; one of them inlines a shared credential that every agent (and every + * reader of the repository) picks up. + */ +@Slf4j +@Component +public class Challenge73 extends FixedAnswerChallenge { + + private static final Pattern TOKEN_PATTERN = Pattern.compile("STAGING_DEPLOY_TOKEN=\"([^\"]+)\""); + + private static final List AGENT_CONTEXT_FILES = + List.of("AGENTS.md", "CLAUDE.md", ".cursor/rules/project.mdc", ".windsurfrules"); + + private final String agentContextPath; + + /** + * Constructor for creating a new Challenge73 object. + * + * @param agentContextPath directory in the dev container that holds the agent instruction files. + */ + public Challenge73(@Value("${AGENT_CONTEXT_PATH}") String agentContextPath) { + this.agentContextPath = agentContextPath; + } + + @Override + @SuppressFBWarnings( + value = "PATH_TRAVERSAL_IN", + justification = "The path is a configured location of the agent context files.") + public String getAnswer() { + var basePath = Path.of(agentContextPath); + for (var fileName : AGENT_CONTEXT_FILES) { + var file = basePath.resolve(fileName); + try { + var content = Files.readString(file, StandardCharsets.UTF_8); + var matcher = TOKEN_PATTERN.matcher(content); + if (matcher.find()) { + return matcher.group(1); + } + } catch (IOException e) { + log.warn("Could not read agent context file {} of challenge 73", file, e); + } + } + log.warn("Could not find the staging token in the agent context files of challenge 73"); + return FILE_MOUNT_ERROR; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1197fd517..9a02ab72f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -90,6 +90,7 @@ management.endpoints.web.exposure.include=auditevents,info,health chalenge_docker_mount_secret=/var/run/secrets2 BASTIONHOSTPATH=.ssh PROJECTSPECPATH=./cursor/rules/project-specification.mdc +AGENT_CONTEXT_PATH=./.devcontainer #--- spring.config.activate.on-profile=kubernetes-vault wrongsecretvalue=wrongsecret diff --git a/src/main/resources/explanations/challenge73.adoc b/src/main/resources/explanations/challenge73.adoc new file mode 100644 index 000000000..a3422f6be --- /dev/null +++ b/src/main/resources/explanations/challenge73.adoc @@ -0,0 +1,25 @@ +=== Challenge 73: Find the Secret in the Agent Instruction Files + +AI coding agents load instruction and context files from the repository on every +session: `AGENTS.md`, `CLAUDE.md`, `.cursor/rules/*.mdc`, `.windsurfrules` and +similar. Because these files are "just documentation", they rarely get the same +review as source code, yet they are read by a model, copied to every developer +machine and committed to version control. + +This repository ships such instruction files with its Dev Container. They live +in the link:https://github.com/OWASP/wrongsecrets/tree/master/.devcontainer[`.devcontainer`] +folder: + +- `.devcontainer/AGENTS.md` +- `.devcontainer/CLAUDE.md` +- `.devcontainer/.cursor/rules/project.mdc` +- `.devcontainer/.windsurfrules` + +One of them inlines a shared credential so that every agent reuses the same +value "for convenience". Read the files and submit the exposed staging token. + +[NOTE] +==== +Nothing is encoded or encrypted here: this is exactly what a leaked agent +context file looks like in the wild. +==== diff --git a/src/main/resources/explanations/challenge73_hint.adoc b/src/main/resources/explanations/challenge73_hint.adoc new file mode 100644 index 000000000..2dd04e3ea --- /dev/null +++ b/src/main/resources/explanations/challenge73_hint.adoc @@ -0,0 +1,15 @@ +The agent instruction files are shipped with the Dev Container in the +`.devcontainer` folder: + +- `.devcontainer/AGENTS.md` +- `.devcontainer/CLAUDE.md` +- `.devcontainer/.cursor/rules/project.mdc` +- `.devcontainer/.windsurfrules` + +Three of them only point at where the shared credential lives. One of them +inlines the value of `STAGING_DEPLOY_TOKEN` in a shell snippet. That value is +the answer. + +If you are not using the Dev Container, you can also read the same files +straight from the repository in the link:https://github.com/OWASP/wrongsecrets/tree/master/.devcontainer[`.devcontainer`] +folder. diff --git a/src/main/resources/explanations/challenge73_reason.adoc b/src/main/resources/explanations/challenge73_reason.adoc new file mode 100644 index 000000000..ca47d928b --- /dev/null +++ b/src/main/resources/explanations/challenge73_reason.adoc @@ -0,0 +1,39 @@ +*Why you should never put a secret in an agent instruction file* + +`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/*.mdc`, `.windsurfrules` and the many +other agent context formats are loaded automatically by coding agents. That +makes them convenient, and that convenience is exactly what turns them into a +secret management problem: + +- They are committed to the repository, so the secret is in the git history + forever and has to be rotated the moment it appears. +- They are copied to every machine that checks out the repository, including + forks, CI runners and personal laptops. +- They are loaded into the model context, so the value can end up in chat + transcripts, telemetry and logs owned by third parties. +- They usually carry a *shared* credential, which is rarely scoped down and + even more rarely rotated. +- Many secret scanners treat documentation files as low priority, so the leak + survives review for a long time. + +---- +What to do instead: + +- Keep credentials out of the instruction files and let the agent read them + from the environment, for example `$STAGING_DEPLOY_TOKEN`. +- Document *which* variable is required and *where* to obtain it, never the + value itself. +- Give every consumer a short-lived, least-privilege credential instead of one + shared token. +- Scan agent instruction files with a secret scanner in pre-commit and CI, just + like you scan source code. +- Treat any secret that ever appeared in agent context as compromised and + rotate it. +---- + +[NOTE] +==== +Skills, rules, prompts, MCP server configurations and agent instruction files +are all code as far as your secret management is concerned. If you would not +hardcode a token in a `.java` file, do not hardcode it in a `CLAUDE.md` either. +==== diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index fe0283331..04ba031b1 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -1104,3 +1104,16 @@ configurations: category: *ai ctf: enabled: true + + - name: Challenge 73 + short-name: "challenge-73" + sources: + - class-name: "org.owasp.wrongsecrets.challenges.docker.Challenge73" + explanation: "explanations/challenge73.adoc" + hint: "explanations/challenge73_hint.adoc" + reason: "explanations/challenge73_reason.adoc" + environments: *all_envs + difficulty: *easy + category: *ai + ctf: + enabled: true diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73RegistrationTest.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73RegistrationTest.java new file mode 100644 index 000000000..f299c34c3 --- /dev/null +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73RegistrationTest.java @@ -0,0 +1,36 @@ +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; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class Challenge73RegistrationTest { + + private static final String EXPECTED_TOKEN = "Ag3nt_C0nt3xt_L3ak3d_T0k3n!"; + + @Autowired private Challenges challenges; + + @Test + void challenge73ShouldBeRegisteredAndDiscoverable() { + var definition = challenges.findByShortName("challenge-73"); + + assertThat(definition).isPresent(); + assertThat(challenges.getChallenge(definition.get())).hasSize(1); + assertThat(challenges.getChallenge(definition.get()).getFirst()) + .isInstanceOf(Challenge73.class); + } + + @Test + void registeredChallenge73ShouldExposeTheLeakedToken() { + var definition = challenges.findByShortName("challenge-73").orElseThrow(); + + var challenge = challenges.getChallenge(definition).getFirst(); + + assertThat(challenge.spoiler().solution()).isEqualTo(EXPECTED_TOKEN); + assertThat(challenge.answerCorrect(challenge.spoiler().solution())).isTrue(); + } +} diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73Test.java new file mode 100644 index 000000000..4bd75da2e --- /dev/null +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73Test.java @@ -0,0 +1,78 @@ +package org.owasp.wrongsecrets.challenges.docker; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.owasp.wrongsecrets.Challenges.ErrorResponses.FILE_MOUNT_ERROR; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class Challenge73Test { + + private static final String DEFAULT_AGENT_CONTEXT_PATH = "./.devcontainer"; + private static final String EXPECTED_TOKEN = "Ag3nt_C0nt3xt_L3ak3d_T0k3n!"; + + private static final List AGENT_CONTEXT_FILES = + List.of("AGENTS.md", "CLAUDE.md", ".cursor/rules/project.mdc", ".windsurfrules"); + + private static void writeAgentContextFiles(Path dir, String token) throws IOException { + for (var fileName : AGENT_CONTEXT_FILES) { + var file = dir.resolve(fileName); + Files.createDirectories(file.getParent()); + Files.writeString(file, "# " + fileName + "\n\nNo secrets here.\n"); + } + Files.writeString( + dir.resolve("CLAUDE.md"), + "# CLAUDE.md\n\nexport STAGING_DEPLOY_TOKEN=\"" + token + "\"\n"); + } + + @Test + void spoilerShouldGiveTheTokenShippedWithTheDevContainer() { + var challenge = new Challenge73(DEFAULT_AGENT_CONTEXT_PATH); + + assertThat(challenge.spoiler().solution()).isEqualTo(EXPECTED_TOKEN); + assertThat(challenge.answerCorrect(EXPECTED_TOKEN)).isTrue(); + } + + @Test + void shippedAgentContextFilesShouldContainTheTokenOnlyOnce() throws IOException { + var occurrences = 0; + for (var fileName : AGENT_CONTEXT_FILES) { + var content = + Files.readString( + Path.of(DEFAULT_AGENT_CONTEXT_PATH).resolve(fileName), StandardCharsets.UTF_8); + occurrences += content.split(EXPECTED_TOKEN, -1).length - 1; + } + + assertThat(occurrences).isEqualTo(1); + } + + @Test + void shouldExtractTheTokenFromTheAgentContextFiles(@TempDir Path dir) throws IOException { + writeAgentContextFiles(dir, "t0k3n-from-the-agent-context"); + + var challenge = new Challenge73(dir.toString()); + + assertThat(challenge.spoiler().solution()).isEqualTo("t0k3n-from-the-agent-context"); + assertThat(challenge.answerCorrect("t0k3n-from-the-agent-context")).isTrue(); + } + + @Test + void incorrectAnswerShouldNotSolveChallenge() { + var challenge = new Challenge73(DEFAULT_AGENT_CONTEXT_PATH); + + assertThat(challenge.answerCorrect("wrong answer")).isFalse(); + assertThat(challenge.answerCorrect("")).isFalse(); + } + + @Test + void shouldReportAnErrorWhenTheAgentContextIsMissing(@TempDir Path dir) { + var challenge = new Challenge73(dir.resolve("does-not-exist").toString()); + + assertThat(challenge.spoiler().solution()).isEqualTo(FILE_MOUNT_ERROR); + } +} From d61285ffb231f3e142e0cdc129815ce347f60f75 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 06:29:15 +0000 Subject: [PATCH 2/6] [pre-commit.ci lite] apply automatic fixes --- .../owasp/wrongsecrets/challenges/docker/Challenge73Test.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73Test.java b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73Test.java index 4bd75da2e..f624f3c7f 100644 --- a/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73Test.java +++ b/src/test/java/org/owasp/wrongsecrets/challenges/docker/Challenge73Test.java @@ -26,8 +26,7 @@ private static void writeAgentContextFiles(Path dir, String token) throws IOExce Files.writeString(file, "# " + fileName + "\n\nNo secrets here.\n"); } Files.writeString( - dir.resolve("CLAUDE.md"), - "# CLAUDE.md\n\nexport STAGING_DEPLOY_TOKEN=\"" + token + "\"\n"); + dir.resolve("CLAUDE.md"), "# CLAUDE.md\n\nexport STAGING_DEPLOY_TOKEN=\"" + token + "\"\n"); } @Test From e030d5a3c9b3184d7c4807e5013dab404f422184 Mon Sep 17 00:00:00 2001 From: kekubhai Date: Wed, 23 Sep 2026 12:49:42 +0530 Subject: [PATCH 3/6] Remove unnecessary PATH_TRAVERSAL_IN suppression on Challenge73.getAnswer() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SpotBugs 4.10.4 no longer flags the method since the file names come from a fixed constant list, so the annotation triggered US_USELESS_SUPPRESSION_ON_METHOD. 🤖 Generated with Codebuff Co-Authored-By: Codebuff --- .../org/owasp/wrongsecrets/challenges/docker/Challenge73.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge73.java b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge73.java index 0ee9dc340..27d67d694 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge73.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/docker/Challenge73.java @@ -2,7 +2,6 @@ import static org.owasp.wrongsecrets.Challenges.ErrorResponses.FILE_MOUNT_ERROR; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -41,9 +40,6 @@ public Challenge73(@Value("${AGENT_CONTEXT_PATH}") String agentContextPath) { } @Override - @SuppressFBWarnings( - value = "PATH_TRAVERSAL_IN", - justification = "The path is a configured location of the agent context files.") public String getAnswer() { var basePath = Path.of(agentContextPath); for (var fileName : AGENT_CONTEXT_FILES) { From 06a1291e70b3e8c3e8ee11d96c47a84250666d29 Mon Sep 17 00:00:00 2001 From: kekubhai Date: Thu, 24 Sep 2026 11:40:02 +0530 Subject: [PATCH 4/6] Build Llama request JSON via Jackson tree API to fix SpotBugs VA_FORMAT_STRING_USES_NEWLINE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with Codebuff Co-Authored-By: Codebuff --- .../kubernetes/llama/LlamaChatController.java | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/llama/LlamaChatController.java b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/llama/LlamaChatController.java index e1b66f88a..322c2c983 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/llama/LlamaChatController.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/llama/LlamaChatController.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; @@ -32,26 +33,18 @@ public LlamaChatController(ObjectMapper objectMapper, @Value("${LLAMAURL}") Stri produces = MediaType.APPLICATION_JSON_VALUE) public ChatResponse chat(@RequestBody ChatRequest request) throws Exception { - var llamaRequest = - """ - { - "messages": [ - { - "role": "user", - "content": %s - } - ], - "temperature": 0.1, - "max_tokens": 128 - } - """ - .formatted(objectMapper.writeValueAsString(request.message())); + ObjectNode llamaRequest = objectMapper.createObjectNode(); + llamaRequest.put("temperature", 0.1); + llamaRequest.put("max_tokens", 128); + var userMessage = llamaRequest.putArray("messages").addObject(); + userMessage.put("role", "user"); + userMessage.put("content", request.message()); var httpRequest = HttpRequest.newBuilder() .uri(URI.create(llamaUrl + "/v1/chat/completions")) .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(llamaRequest)) + .POST(HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(llamaRequest))) .build(); var response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); From b618d9f5387d6abcb188d210124285f79fcc43a9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2026 06:12:28 +0000 Subject: [PATCH 5/6] [pre-commit.ci lite] apply automatic fixes --- .../challenges/kubernetes/llama/LlamaChatController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/llama/LlamaChatController.java b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/llama/LlamaChatController.java index 322c2c983..c9f50e692 100644 --- a/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/llama/LlamaChatController.java +++ b/src/main/java/org/owasp/wrongsecrets/challenges/kubernetes/llama/LlamaChatController.java @@ -44,7 +44,8 @@ public ChatResponse chat(@RequestBody ChatRequest request) throws Exception { HttpRequest.newBuilder() .uri(URI.create(llamaUrl + "/v1/chat/completions")) .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(llamaRequest))) + .POST( + HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(llamaRequest))) .build(); var response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); From 302e4a4d254f11271415b467477719bd72872dfe Mon Sep 17 00:00:00 2001 From: kekubhai Date: Thu, 24 Sep 2026 12:04:23 +0530 Subject: [PATCH 6/6] Fix Challenge74 class-name mismatch that broke challenge page submissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The config pointed at k8s.llama.Challenge74 but the class lives in kubernetes.llama, so findChallenge() returned empty and submitting an answer on the challenge page threw ChallengeConfigurationException, failing the Cypress incorrect-alert e2e test. 🤖 Generated with Codebuff Co-Authored-By: Codebuff --- src/main/resources/wrong-secrets-configuration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/wrong-secrets-configuration.yaml b/src/main/resources/wrong-secrets-configuration.yaml index 0dd621a6e..b3d42d368 100644 --- a/src/main/resources/wrong-secrets-configuration.yaml +++ b/src/main/resources/wrong-secrets-configuration.yaml @@ -1121,7 +1121,7 @@ configurations: - name: Challenge 74 short-name: "challenge-74" sources: - - class-name: "org.owasp.wrongsecrets.challenges.k8s.llama.Challenge74" + - class-name: "org.owasp.wrongsecrets.challenges.kubernetes.llama.Challenge74" explanation: "explanations/challenge74.adoc" hint: "explanations/challenge74_hint.adoc" reason: "explanations/challenge74_reason.adoc"