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.
First MOAD-0003 (Leaked Context) flagship this session. Surfaced via
scanner enhancement: commit 1f48798 (Java ThreadLocal-scoped .set fix)
dropped wildfly M3 noise from 4840 -> 37, exposing this real defect.
Defect: ElytronSecurityIntegration.java:38 declares
private final ThreadLocal<SecurityContext> securityContext = new ThreadLocal<>();
with setSecurityContext() calling .set(context) and ZERO corresponding
.remove() / .set(null) anywhere in the WildFly codebase (verified by
grep -rn). JCA WorkManager reuses pool threads across Work items from
different security principals; a leftover SecurityContext from prior
Work is visible to any subsequent Work that reads getSecurityContext()
before installing its own — which WildflyWorkWrapper.runWork() does
exactly to decide whether to use Elytron-runWork or super.runWork().
Fix: 2-file surgical patch (no SPI change):
1. setSecurityContext(null) now calls .remove() (clear ThreadLocal,
prevent classloader retention)
2. WildflyWorkWrapper.runWork() wraps body in try/finally that calls
setSecurityContext(null) after the Work item completes
This is the inverse pipeline from CWE-407 flagships: scanner improved
its signal-to-noise so triage could find what raw scanning could not
have ranked.