CVE-2022-31690: Privilege Escalation in spring-security-oauth2-client

Engineering | Steve Riesenberg | October 31, 2022 | ...

Spring Security 5.6.9 and 5.7.5 released on October 31st, 2022 included a fix for CVE-2022-31690 affecting the mapping of authorized scopes in spring-security-oauth2-client. Users are encouraged to update as soon as possible.

Impact

Users who have applied the mitigation should take note of the following impact:

No authorized scopes are mapped to the principal (current user) when the Authorization Server (AS) responds to the OAuth2 Access Token Response with an empty or missing scope parameter.

If you are affected by this vulnerability, users will not be granted any authorities beginning with SCOPE_ when the AS does not return scopes. Only the special authority ROLE_USER is given to the principal.

Note

Beginning with 6.0, the special authority is changed to OAUTH2_USER (or OIDC_USER). See Using a GrantedAuthoritiesMapper in the 6.0 reference documentation for more information.

If additional authorities are required for your application, you should register a GrantedAuthoritiesMapper @Bean to provide the needed authorities, as in the following example:

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests((authorize) -> authorize
				.mvcMatchers(HttpMethod.GET, "/messages").hasAuthority("SCOPE_read")
				// ...
				.anyRequest().authenticated()
			)
			.oauth2Login(Customizer.withDefaults());
		return http.build();
	}

	@Bean
	public GrantedAuthoritiesMapper userAuthoritiesMapper() {
		return (authorities) -> {
			if (!authorities.isEmpty() && authorities.stream()
					.map(GrantedAuthority::getAuthority)
					.anyMatch(authority -> authority.startsWith("SCOPE_"))) {
				// AS returned scopes that are mapped to SCOPE_ by Spring Security
				return authorities;
			}

			// AS returned no scopes, either because none were granted or because requested == granted
			// See https://www.rfc-editor.org/rfc/rfc6749#section-5.1 and your AS documentation
			// You can access the ID Token or UserInfo attributes to map authorities based on the user:

			Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
			authorities.forEach(authority -> {
				if (OidcUserAuthority.class.isInstance(authority)) {
					OidcUserAuthority oidcUserAuthority = (OidcUserAuthority) authority;
					OidcIdToken idToken = oidcUserAuthority.getIdToken();
					// ...
				} else if (OAuth2UserAuthority.class.isInstance(authority)) {
					OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority) authority;
					Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
					// ...
				}
			});

			return grantedAuthorities;

			// Alternatively, provide a fallback set of authorities that make sense for your application
			// return AuthorityUtils.createAuthorityList("ROLE_USER", "SCOPE_read");
		};
	}

}

Warning

It is not recommended to simply map authorities from the ClientRegistration.

Get the Spring newsletter

Stay connected with the Spring newsletter

Subscribe

Get ahead

VMware offers training and certification to turbo-charge your progress.

Learn more

Get support

Tanzu Spring offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Learn more

Upcoming events

Check out all the upcoming events in the Spring community.

View all