Skip to content

Conversation

@ttddyy
Copy link
Contributor

@ttddyy ttddyy commented Nov 23, 2025

We encountered an issue where authentication was being mixed across threads.
During our analysis, we discovered that SecurityContextHolderThreadLocalAccessor propagates the same SecurityContext to other threads when using Micrometer Context Propagation.

Below is a simplified example that demonstrates the problem:

Authentication authA = ...
Authentication authB = ...

// Set authA in the main thread
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authA);

Runnable runnable = () -> {
    // This retrieves the *same* SecurityContext instance as the main thread
    SecurityContext context = SecurityContextHolder.getContext();
    context.setAuthentication(authB);
};

// Executor integrated with Micrometer Context Propagation
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
executor.afterPropertiesSet();

executor.execute(runnable);

// Wait until runnable finishes
...

// Authentication has now changed unexpectedly
SecurityContext current = SecurityContextHolder.getContext();
current.getAuthentication();  // returns authB instead of authA

When Micrometer context propagation is in use, the current implementation effectively shares the SecurityContext instance between threads. This is generally not recommended and can cause subtle and hard-to-diagnose behavior, such as authentication leakage across threads.

We understand that swapping the Authentication directly is rarely a good practice. However, if a new SecurityContext had been used for the different thread, it would have been isolated and harmless. The underlying issue happens only because the same SecurityContext instance is shared across threads.

Proposed Change

This PR updates SecurityContextHolderThreadLocalAccessor to create a new SecurityContext whenever a thread switch happens, and propagte only the Authentication.

I have targetted the PR to 6.5.x branch as I consider it is a bug and should be fixed in there and up.

`SecurityContextHolderThreadLocalAccessor` currently propagates the
same `SecurityContext` to other threads when Micrometer
Context Propagation is used. This leads to unintended sharing of
mutable state and can cause authentication to leak between threads.

This change updates the accessor to create a new
`SecurityContext` for the target thread while reusing only the
`Authentication` value. Each thread now receives its own
`SecurityContext` instance, preventing cross-thread interference and
aligning with recommended `SecurityContext` usage.

Signed-off-by: Tadaya Tsuyukubo <tadaya@ttddyy.net>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants