Misconfigurations that bite

Spring Security · lesson 15 of 31 · 4 min read

Recognise the handful of mistakes behind most Spring Security bugs and security holes.

Open this lesson in the learning hub

Key points

  • A broad pattern above a narrow one wins silently. /api/** before /api/admin/** means the admin rule never runs.
  • Spring fails fast if you add rules after anyRequest(), but never warns about a shadowed pattern. Order by specificity.
  • Disabling CSRF on a cookie-authenticated app is a real vulnerability, not a convenience. Only token APIs may switch it off.
  • hasRole("ROLE_ADMIN") looks for ROLE_ROLE_ADMIN. Use hasRole("ADMIN") instead.
  • Unexpected 403 on error pages? In Spring Security 6 authorization also runs on the ERROR dispatch — permit it explicitly.
  • Never log raw passwords or tokens, and never return stack traces to clients. Both leak straight into log aggregators.

Example

// WRONG: the broad rule matches first, so the admin rule is dead code
http.authorizeHttpRequests(a -> a
    .requestMatchers("/api/**").authenticated()
    .requestMatchers("/api/admin/**").hasRole("ADMIN")
    .anyRequest().denyAll());

// RIGHT: most specific first, error dispatch permitted, deny by default
http.authorizeHttpRequests(a -> a
    .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
    .requestMatchers("/api/admin/**").hasRole("ADMIN")
    .requestMatchers("/api/**").authenticated()
    .anyRequest().denyAll());

Most Spring Security bugs are ordering, prefixes, or a CSRF switch flipped for the wrong reason.

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.