java-topology/defects/wildfly/patch/wildfly-0002-elytronsecuritydomain-isvalid-threadlocal-leak.patch
russell@unturf.com 2eea7d128c
4 follow-up patches shipped: wildfly-0002 + wildfly-0003 + log4j2-0001 + nakama-0001
Acting on the 4 borderline candidates flagged in the session-summary intel.
All 4 surfaced after the unmoad scanner enhancements cleared M3/M4 noise.

UNDF-1306 wildfly-0002 (HIGH) - ElytronSecurityDomainContextImpl.isValid()
  sets currentIdentity ThreadLocal with no paired cleanup contract. Subject
  populated at line 69 is the canonical handover; the ThreadLocal stash leaks
  to next request on the pool thread. Fix: drop the .set(identity) line.

UNDF-1307 wildfly-0003 (LOW) - TransactionRollbackSetupAction.depth.set(null)
  should be depth.remove() to fully delete the ThreadLocal entry; current
  pattern leaves null binding pinning the WildFly classloader during
  undeploy/redeploy. Functional clear, classloader-retention only.

UNDF-1308 log4j2-0001 (HIGH) - Log4jMDCAdapter.clear() only clears the
  log4j ThreadContext map, NOT the SLF4J pushByKey/popByKey stacks
  (mapOfStacks ThreadLocal). SLF4J spec mandates clear() means "clear
  all MDC". Per-key Deques accumulate across requests. Fix: add clear()
  to ThreadLocalMapOfStacks (calls tlMapOfStacks.remove()) and call from
  the public clear().

UNDF-1309 nakama-0001 (HIGH MOAD-0004) - social/social.go logs OAuth
  access tokens, ID tokens, oauth2.Token objects (incl. refresh tokens),
  Steam publisherKey + ticket at debug level via zap.String/zap.Any.
  11 call sites. Fix: replace value-logging with shape-logging (token_len,
  has_token bool) — preserves debug value, redacts secret bytes.

First MOAD-0004 patch this session. Companion to the 3 MOAD-0003 patches
(wildfly-0001/0002/0003) extending the inverse-pipeline pattern across
projects: scanner enhancement -> noise reduction -> human triage finds
defects that were buried.

Total session flagships: 9 (was 6) — 5 CWE-407 + 3 MOAD-0003 + 1 MOAD-0004.
2026-04-26 12:30:28 -04:00

55 lines
3.1 KiB
Diff

# UNDF: UNDF-2026-000001306
# CWE-668 / MOAD-0003: A Leaked Context — ElytronSecurityDomainContextImpl.isValid()
# sets ThreadLocal currentIdentity with no
# paired cleanup contract
#
# Defect: webservices/server-integration/src/main/java/org/jboss/as/webservices/security/
# ElytronSecurityDomainContextImpl.java:68
#
# SecurityIdentity identity = authenticate(username, (String) password);
# if (identity == null) {
# return false;
# }
# this.currentIdentity.set(identity); // <-- here
# SubjectUtil.fromSecurityIdentity(identity, subject);
# return true;
#
# The class has three currentIdentity-setter call sites:
# - line 68: isValid() -> NO contractual paired cleanup
# - line 80: runAs() -> properly clears via try/finally
# - line 96: pushSubjectContext() -> paired with cleanupSubjectContext()
#
# isValid() exists to validate credentials and populate the caller's Subject
# (line 69). Once it returns true the caller already has the SecurityIdentity
# inside the populated Subject — no need to also stash a copy in the
# per-thread currentIdentity. JBossWS/CXF callers using isValid() purely for
# credential validation (without proceeding to runAs() or
# pushSubjectContext()/cleanupSubjectContext()) leak the previous request's
# SecurityIdentity into the next Work item on the same pool thread.
#
# Fix: drop the currentIdentity.set(identity) line in isValid(). Callers that
# actually need the per-thread identity install should use pushSubjectContext()
# (paired with cleanupSubjectContext()) or runAs() (paired with try/finally
# currentIdentity.remove() inside the same method). The Subject populated at
# line 69 remains the canonical handover for credential-validation callers.
#
# Companion to wildfly-0001 (UNDF-1305): same MOAD-0003 family, different
# entry point, surfaced after the same scanner improvement (unmoad commit
# 1f48798) cleared 99.2% of the M3 noise that had buried both findings.
--- a/webservices/server-integration/src/main/java/org/jboss/as/webservices/security/ElytronSecurityDomainContextImpl.java
+++ b/webservices/server-integration/src/main/java/org/jboss/as/webservices/security/ElytronSecurityDomainContextImpl.java
@@ -65,7 +65,11 @@ public class ElytronSecurityDomainContextImpl implements SecurityDomainContext {
if (identity == null) {
return false;
}
- this.currentIdentity.set(identity);
+ // Do NOT stash identity into the per-thread currentIdentity here.
+ // isValid() exists to validate credentials and populate the caller's
+ // Subject (next line). Stashing into the ThreadLocal without a paired
+ // cleanup contract leaks this identity into the next Work item that
+ // runs on the same pool thread. Callers that need per-thread identity
+ // install should use pushSubjectContext() / cleanupSubjectContext()
+ // (paired) or runAs() (auto-cleared in finally).
SubjectUtil.fromSecurityIdentity(identity, subject);
return true;
}