Broken Authentication

How to Fix Broken Authentication in Spring Boot [March 2026] [CVE-2021-26074]

[Updated month year] Updated CVE-2021-26074

Overview

The CVE-2021-26074 vulnerability affects Atlassian Connect Spring Boot (ACSB) prior to 2.1.3 where the app could inadvertently accept context JWTs at lifecycle endpoints (such as installation) that should only accept server-to-server (S2S) JWTs. An attacker could leverage this to trigger authenticated lifecycle events like re-installation, potentially manipulating app state or gaining persistence. This manifests as Broken Authentication (CWE-287) in a Spring Boot Java app that uses ACSB for Atlassian Connect integrations. The real-world risk is elevated because an attacker can abuse the token flow to impersonate installation or re-install events, bypassing intended authentication restrictions. CVE-2021-26074 documents this flaw and the surrounding context for ACSB versions prior to 2.1.3. The remediation path is to upgrade ACSB to 2.1.3 or later and, at the code level, strengthen JWT handling to ensure lifecycle endpoints only accept S2S tokens and reject context tokens or tokens that do not meet the expected type. In practice, Spring Boot apps should rely on the updated ACSB library that enforces the proper token type semantics, and/or add explicit checks on token_claims (token_type) and endpoint usage to prevent misuse during lifecycle flows.

Affected Versions

1.1.0 - 2.1.2

Code Fix Example

Spring Boot API Security Remediation
VULNERABLE PATTERN (no token-type checks):

import io.jsonwebtoken.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class JwtAuthFilter implements Filter {
    private static final String SHARED_SECRET = "secret";
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws java.io.IOException, javax.servlet.ServletException {
        HttpServletRequest http = (HttpServletRequest) req;
        String auth = http.getHeader("Authorization");
        if (auth != null && auth.startsWith("JWT ")) {
            String token = auth.substring(4);
            try {
                Jws<Claims> claims = Jwts.parser().setSigningKey(SHARED_SECRET.getBytes())
                        .parseClaimsJws(token);
                chain.doFilter(req, res);
                return;
            } catch (JwtException e) {
                ((HttpServletResponse) res).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return;
            }
        }
        chain.doFilter(req, res);
    }
}

FIXED PATTERN (enforce token_type on lifecycle endpoints):

import io.jsonwebtoken.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class JwtAuthFilter implements Filter {
    private static final String SHARED_SECRET = "secret";
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws java.io.IOException, javax.servlet.ServletException {
        HttpServletRequest http = (HttpServletRequest) req;
        String auth = http.getHeader("Authorization");
        if (auth != null && auth.startsWith("JWT ")) {
            String token = auth.substring(4);
            try {
                Jws<Claims> claims = Jwts.parser().setSigningKey(SHARED_SECRET.getBytes())
                        .parseClaimsJws(token);
                String path = http.getRequestURI();
                boolean isLifecycle = path.startsWith("/lifecycle") || path.startsWith("/install");
                String tokenType = claims.getBody().get("token_type", String.class);
                if (isLifecycle && (tokenType == null || !"s2s".equals(tokenType))) {
                    ((HttpServletResponse) res).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                    return;
                }
                chain.doFilter(req, res);
                return;
            } catch (JwtException e) {
                ((HttpServletResponse) res).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return;
            }
        }
        chain.doFilter(req, res);
    }
}

CVE References

Choose which optional cookies to allow. You can change this any time.