A review checklist that finds real holes
The handful of settings that account for most production security incidents.
Open this lesson in the learning hubKey points
- CSRF disabled on a cookie-authenticated app. Disabling it is correct for a token-authenticated API and dangerous for anything using session cookies. The same line is right in one place and a hole in the other.
- CORS with credentials and a wildcard origin. The specification forbids it, but a permissive custom filter can reproduce the effect and expose authenticated endpoints to any site.
- permitAll on the wrong matcher. A pattern such as
/api/**intended to open one endpoint opens all of them. Confirm with an actual request, not by reading the pattern. - Actuator exposed.
/actuator/envand/actuator/configpropscan print configuration including credentials whose key name does not match the masking patterns. - Stack traces returned to clients. They leak framework versions, file paths and SQL. Boot masks these by default; a custom handler often unmasks them without meaning to.
- Default or shared credentials anywhere - a seeded admin user, a fixed JWT signing key committed for local development, a service account shared between environments.
Example
# Probe the running application. This finds more than reading configuration.
# 1. Is anything reachable unauthenticated that should not be?
$ curl -s -o /dev/null -w "%{http_code} %{url_effective}\n" \
localhost:8080/api/orders \
localhost:8080/api/admin/users \
localhost:8080/actuator/env \
localhost:8080/actuator/heapdump
# Anything other than 401/403/404 on those last two is a finding.
# 2. Are the security headers present?
$ curl -sI localhost:8080/ | grep -iE \
"strict-transport|x-content-type|x-frame|content-security"
# 3. Does CORS reflect an arbitrary origin back with credentials?
$ curl -sI -H "Origin: https://evil.example" localhost:8080/api/orders \
| grep -i "access-control-allow"
# allow-origin: https://evil.example WITH allow-credentials: true
# -> any site can make authenticated calls on a user behalf
# 4. Object-level authorization - the one automated scanners miss.
$ curl -s -H "Authorization: Bearer $USER_A_TOKEN" \
localhost:8080/api/orders/<an order belonging to user B>
# 200 means broken object-level authorization. This is the big one.
---
# Sane defaults to assert in a test rather than trust:
#
# csrf enabled for cookie auth, disabled only for token APIs
# sessionCreationPolicy STATELESS for APIs
# cors explicit origin list, never a wildcard with credentials
# actuator health + info public; everything else authenticated
# or on a separate management port
# error responses no stack trace, no SQL, no framework version
# headers HSTS, X-Content-Type-Options, frame-options, CSP
Probe the running application rather than reading config - and test object-level access with a second user, which is the check most often skipped.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Security course, and every lesson in it is listed on the Spring Security contents page.