Welcome to the OWASP WrongSecrets project! This document provides GitHub Copilot with essential context to help you contribute effectively to this educational cybersecurity project.
WrongSecrets is an intentionally vulnerable Spring Boot application designed to teach secrets management through real-world examples of what NOT to do. The project contains 56+ challenges where developers must find exposed secrets in code, configuration files, containers, and cloud deployments.
wrongsecrets/
├── src/main/java/org/owasp/wrongsecrets/
│ ├── challenges/ # Challenge implementations
│ │ ├── docker/ # Docker-specific challenges
│ │ ├── cloud/ # Cloud provider challenges (AWS/GCP/Azure)
│ │ ├── kubernetes/ # K8s and Vault challenges
│ │ └── FixedAnswerChallenge.java # Base class for simple challenges
│ ├── definitions/ # Challenge metadata and configuration
│ ├── oauth/ # Authentication components
│ └── WrongSecretsApplication.java # Main Spring Boot application
├── src/test/java/ # Test files mirroring main structure
├── src/main/resources/ # Configuration files and web assets
├── .github/workflows/ # CI/CD pipelines
├── docs/ # Project documentation
└── k8s/, aws/, gcp/, azure/ # Deployment configurations
- Framework: Spring Boot 3.5.x
- Java Version: 23 (configured in pom.xml)
- Build Tool: Maven (use
./mvnw) - Testing: JUnit 5, Spring Boot Test
- Container: Docker + Kubernetes
- Cloud: AWS, GCP, Azure integrations
- Frontend: Thymeleaf templates, Bootstrap CSS
For challenges with fixed answers (most common):
@Component
public class Challenge[Number] extends FixedAnswerChallenge {
private final RuntimeEnvironment runtimeEnvironment;
public Challenge[Number](RuntimeEnvironment runtimeEnvironment) {
this.runtimeEnvironment = runtimeEnvironment;
}
@Override
public String getAnswer() {
// Return the secret that users need to find
return "the-secret-value";
}
@Override
public boolean canRunInCTFMode() {
return true; // Set to false if challenge can't run in CTF mode
}
@Override
public RuntimeEnvironment.Environment supportedRuntimeEnvironments() {
return RuntimeEnvironment.Environment.DOCKER; // or ALL, K8S, etc.
}
}For challenges with dynamic answers:
@Component
public class Challenge[Number] implements Challenge {
@Override
public Spoiler spoiler() {
return new Spoiler(calculateAnswer());
}
@Override
public boolean answerCorrect(String answer) {
return Objects.equals(calculateAnswer(), answer);
}
private String calculateAnswer() {
// Complex logic here
}
}Challenge tests should:
@ExtendWith(MockitoExtension.class)
class Challenge[Number]Test {
@Mock
private RuntimeEnvironment runtimeEnvironment;
@InjectMocks
private Challenge[Number] challenge;
@Test
void answerCorrect() {
// Test the correct answer
assertTrue(challenge.answerCorrect(challenge.spoiler().solution()));
}
@Test
void answerIncorrect() {
// Test incorrect answers
assertFalse(challenge.answerCorrect("wrong-answer"));
}
@Test
void canRunInCTFMode() {
// Test CTF mode support
assertTrue(challenge.canRunInCTFMode());
}
}- Package naming: Follow existing structure under
org.owasp.wrongsecrets - Class naming:
- Challenges:
Challenge[Number](e.g.,Challenge1,Challenge42) - Tests:
Challenge[Number]Test
- Challenges:
- Formatting: Use standard Spring Boot/Google Java style
- Imports: Avoid wildcard imports, group logically
- Documentation: JavaDoc for public APIs, inline comments for complex logic
- Configuration: Use
@ConfigurationPropertiesfor external config - Profiles: Support
docker,k8s,aws,gcp,azureprofiles - Components: Use
@Component,@Service,@Controllerappropriately - Environment: Access via
RuntimeEnvironmentservice, not direct@Value
When writing framework code (not challenge vulnerabilities):
- ✅ Use parameterized queries
- ✅ Validate and sanitize inputs
- ✅ Implement proper authentication/authorization
- ✅ Follow OWASP secure coding practices
- ✅ Use secure random generators
- ✅ Avoid hardcoded credentials in framework code
When creating challenge vulnerabilities (educational content):
- ✅ Document the vulnerability type clearly
- ✅ Ensure vulnerability is realistic and educational
- ✅ Include hints and explanations for learners
- ✅ Make secrets discoverable but not trivial
- Determine challenge type: Fixed answer or dynamic?
- Choose appropriate package:
docker/,cloud/,kubernetes/ - Implement challenge class: Extend
FixedAnswerChallengeor implementChallenge - Add corresponding test: Mirror the package structure in
src/test/ - Update configuration: Add to
ChallengeDefinitionsConfigurationif needed - Document: Add challenge description and hints
# Build and compile
./mvnw clean compile
# Run tests
./mvnw test
# Run application locally
./mvnw spring-boot:run
# Run with specific profile
./mvnw spring-boot:run -Dspring.profiles.active=docker
# Run specific test
./mvnw test -Dtest=Challenge1Test# Build container
docker build -t wrongsecrets .
# Run locally
docker run -p 8080:8080 -p 8090:8090 wrongsecrets- Unit tests: Test challenge logic, answer validation
- Integration tests: Test Spring context, controller endpoints
- E2E tests: Cypress tests for UI interactions
- Profile tests: Test different environment configurations
// Arrange
when(runtimeEnvironment.getRuntimeEnvironment())
.thenReturn(RuntimeEnvironment.Environment.DOCKER);
// Act
String result = challenge.getAnswer();
// Assert
assertThat(result).isEqualTo("expected-secret");Common environment variables used in challenges:
SPRING_PROFILES_ACTIVE: Runtime environment (docker, k8s, aws, etc.)K8S_ENV: Kubernetes environment flagwrongsecret[number]: Challenge-specific secrets- Cloud-specific: AWS/GCP/Azure credentials and configurations
- Fixed challenges: Use caching via
FixedAnswerChallenge - Heavy operations: Cache results, use lazy initialization
- External calls: Mock in tests, handle failures gracefully
- Memory: Be mindful of static collections and caching
- README.md: Keep setup instructions current
- CONTRIBUTING.md: Follow established patterns
- JavaDoc: Document public APIs and complex logic
- Challenge hints: Provide educational guidance without giving away answers
- ❌ Don't expose real secrets in challenge code
- ❌ Don't break existing challenge numbering
- ❌ Don't hardcode environment-specific values
- ❌ Don't skip tests for new functionality
- ❌ Don't ignore existing code patterns
- ❌ Don't modify unrelated challenges when adding new ones
- Documentation: Check
docs/directory for detailed guides - Existing code: Look at similar challenges for patterns
- Tests: Examine test files for usage examples
- GitHub Issues: Search existing issues and discussions
- OWASP Slack: Join #project-wrongsecrets channel
Remember: This is an educational project teaching security through intentionally vulnerable examples. Balance realistic vulnerabilities with clear learning outcomes while keeping the framework itself secure and maintainable.