OWASP - Security Misconfiguration
By Admin
•
November 9, 2025
Security Misconfiguration is one of the most common and lethal Java issues.It's when developers deploy code securely written but insecurely configured — leaking data, exposing admin consoles, or leaving defaults in production.
Bad Example — Security Misconfiguration
Here, a Spring Boot app:
- Runs in debug mode
- Uses a default password
- Exposes actuator endpoints
- Returns stack traces to users
// BAD CONFIGURATION EXAMPLE (application.properties)
server.port=8080
spring.profiles.active=dev
# ❌ Debug mode on — leaks stack traces and internal info
server.error.include-message=always
server.error.include-stacktrace=always
# ❌ Default credentials (never changed)
spring.datasource.username=admin
spring.datasource.password=admin123
# ❌ All Actuator endpoints exposed publicly
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
# ❌ Missing security
spring.security.user.name=admin
spring.security.user.password=admin
// Controller intentionally verbose error handling
@RestController
public class LoginController {
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
// ❌ Raw errors reveal internals
if ("admin".equals(username)) {
throw new RuntimeException("Database connection failed: jdbc:mysql://localhost:3306/appdb");
}
return "Login successful";
}
}
⚠️ What's wrong
- Debug/stack traces leak server internals → information disclosure.
- Default passwords → trivial to guess.
- Overexposed actuator endpoints = remote access to metrics, env, shutdown.
- Exposes DB connection info.
- Violates OWASP A05 – Security Misconfiguration and CWE-16 / CWE-200.
✅ Good Example — Secure Configuration
application-prod.properties
# ✅ Secure production configuration
server.port=8443
spring.profiles.active=prod
# ✅ Hide error details from users
server.error.include-message=never
server.error.include-stacktrace=never
# ✅ Externalize credentials using environment variables
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASS}
# ✅ Restrict actuator endpoints
management.endpoints.web.exposure.include=health,info
management.endpoint.health.show-details=never
management.server.port=9001
# ✅ Strong random credentials or integrate with Vault/KMS
spring.security.user.name=${APP_USER}
spring.security.user.password=${APP_PASS}
Hardened Controller
@RestController
public class SecureLoginController {
@PostMapping("/login")
public ResponseEntity<String> login(@RequestParam String username, @RequestParam String password) {
try {
boolean valid = AuthService.validateUser(username, password);
if (!valid) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body("Invalid credentials");
}
return ResponseEntity.ok("Login successful");
} catch (Exception e) {
// ✅ Generic message, no stack trace
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("An internal error occurred. Please try again later.");
}
}
}
✅ Why this is secure
- Disables detailed error output.
- Hides stack traces and DB info.
- Uses environment variables or secrets managers, not hardcoded credentials.
- Limits Actuator to safe endpoints (no /env, /beans, /shutdown).
- Uses least privilege principle for credentials.
- Explicitly separates dev and prod profiles.
Security Best Practices
Area | Secure Design Action |
Error Handling | Show generic messages; log details only on server. |
Credentials | Never hardcode; use environment variables or secrets vault. |
Debug Flags | Disable in production (no verbose stack traces). |
Actuator / Admin Endpoints | Expose only minimal safe endpoints, protect with auth. |
Server Headers | Remove Server, X-Powered-By headers in production. |
Transport Security | Use HTTPS (TLS 1.2+), not HTTP. |
File Permissions | Run with non-root user and least privilege. |
Dependency Hygiene | Patch outdated frameworks and libraries. |
TL;DR
Bad: "It's just dev mode — ship it."Good: "Every environment has hardened, principle-of-least-privilege configuration."
