You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cache keys are written to logs at LogLevel.Warning. For the application's own caches that is usually harmless — the keys are entity ids. For the IDistributedCache adapter added in #121 it is not: IDistributedCache keys are chosen by the consumer and can be secrets. Under ASP.NET Core session the key is the session identifier (the GUID SessionMiddleware decrypts from the client's cookie); rate limiters commonly key by API key or client IP.
The adapter fingerprints keys in its own two log messages, but it passes the composed CacheKey to the backing provider, which logs it. A Redis blip raises the inner-cache warning paths and writes session identifiers to the log — CWE-532. Warning is enabled in production, so this is not a debug-only exposure.
A logged session id is not by itself enough to hijack a session (forging the cookie needs the DataProtection key), but logs have a far wider audience and longer retention than the session store — aggregation platforms, support bundles, on-call access — and anyone with Redis read access, an RDB backup or a support dump goes from a logged id straight to that user's session contents.
Proposed fix
Add a per-cache switch, honored at every site that logs a key:
// ICacheOptionsboolLogKeys{get;}// default true
Implemented as public bool LogKeys { get; set; } = true; on InMemoryCacheOptions, InMemoryRedisCacheOptions and RedisCacheOptions, surfaced through MultilayerCacheBase / RedisCacheBase, and consumed by a shared helper that renders either the key or a short SHA-256 digest — the same digest shape UiPathDistributedCache.Fingerprint already uses, so occurrences of one key stay correlatable in a log without revealing it. AddDistributedCache then sets LogKeys = false on the private provider's cloned options, alongside the CacheKeyStrategy neutralization it already does.
UiPathDistributedCache.Fingerprint should move to that shared helper rather than being duplicated.
Site inventory
Measured on feat/distributed-cache @ a7c0f6d — declarations taking CacheKey/RedisKey, and their call sites:
File
LoggerMessage declarations
Call sites
MultilayerCache.cs
15
48
MultilayerHashCache.cs
17
36
Redis/RedisHashCache.cs
3
6
Redis/RedisCache.cs
3
6
CacheEventPublisher.cs
1 (LogRaiseEvent)
—
The Warning-level ones — the production exposure — are MultilayerHashCache.LogInnerCacheRefreshError, LogInnerCacheContainsError, LogInnerCacheSetMetadataFailed, LogInnerCacheRemoveError, LogInnerCacheSetError, their MultilayerCache equivalents, and RedisHashCache/RedisCacheLogLargeValueDetected.
Constraints
Must be applied to all of the above, not just the hash path. Honoring the flag in some classes and ignoring it in others reproduces the inert-setting defect class feat(cache): IDistributedCache adapter with case-sensitive keys and byte[] serialization #121 hit three times (AllowUnboundedEntries being ignored, CacheKeyStrategy unread by RedisHashCache, the tier Enabled switch checked too late).
Do not redact via CacheKey.ToString(). It looks like a one-line fix covering every current and future site, but CacheKey exposes an implicit operator string that is used functionally — PrefixRedisKeyStrategy.GetRedisKey composes the physical key with string.Join(Separator, Prefix, key) — so redacting either corrupts key composition or leaves ToString() and the implicit conversion disagreeing.
Keys stay verbatim in Redis, for parity with Microsoft.Extensions.Caching.StackExchangeRedis. This issue covers logs only; KEYS/SCAN output and RDB snapshots still contain them, which is documented in docs/reference/settings.md.
Interim state
#121 documents the exposure in docs/reference/settings.md under Caching:Distributed so an operator can scope log access or filter the UiPath.Caching categories until this lands.
Problem
Cache keys are written to logs at
LogLevel.Warning. For the application's own caches that is usually harmless — the keys are entity ids. For theIDistributedCacheadapter added in #121 it is not:IDistributedCachekeys are chosen by the consumer and can be secrets. Under ASP.NET Core session the key is the session identifier (the GUIDSessionMiddlewaredecrypts from the client's cookie); rate limiters commonly key by API key or client IP.The adapter fingerprints keys in its own two log messages, but it passes the composed
CacheKeyto the backing provider, which logs it. A Redis blip raises the inner-cache warning paths and writes session identifiers to the log — CWE-532. Warning is enabled in production, so this is not a debug-only exposure.A logged session id is not by itself enough to hijack a session (forging the cookie needs the DataProtection key), but logs have a far wider audience and longer retention than the session store — aggregation platforms, support bundles, on-call access — and anyone with Redis read access, an RDB backup or a support dump goes from a logged id straight to that user's session contents.
Proposed fix
Add a per-cache switch, honored at every site that logs a key:
Implemented as
public bool LogKeys { get; set; } = true;onInMemoryCacheOptions,InMemoryRedisCacheOptionsandRedisCacheOptions, surfaced throughMultilayerCacheBase/RedisCacheBase, and consumed by a shared helper that renders either the key or a short SHA-256 digest — the same digest shapeUiPathDistributedCache.Fingerprintalready uses, so occurrences of one key stay correlatable in a log without revealing it.AddDistributedCachethen setsLogKeys = falseon the private provider's cloned options, alongside theCacheKeyStrategyneutralization it already does.UiPathDistributedCache.Fingerprintshould move to that shared helper rather than being duplicated.Site inventory
Measured on
feat/distributed-cache@ a7c0f6d — declarations takingCacheKey/RedisKey, and their call sites:LoggerMessagedeclarationsMultilayerCache.csMultilayerHashCache.csRedis/RedisHashCache.csRedis/RedisCache.csCacheEventPublisher.csLogRaiseEvent)The
Warning-level ones — the production exposure — areMultilayerHashCache.LogInnerCacheRefreshError,LogInnerCacheContainsError,LogInnerCacheSetMetadataFailed,LogInnerCacheRemoveError,LogInnerCacheSetError, theirMultilayerCacheequivalents, andRedisHashCache/RedisCacheLogLargeValueDetected.Constraints
AllowUnboundedEntriesbeing ignored,CacheKeyStrategyunread byRedisHashCache, the tierEnabledswitch checked too late).CacheKey.ToString(). It looks like a one-line fix covering every current and future site, butCacheKeyexposes an implicitoperator stringthat is used functionally —PrefixRedisKeyStrategy.GetRedisKeycomposes the physical key withstring.Join(Separator, Prefix, key)— so redacting either corrupts key composition or leavesToString()and the implicit conversion disagreeing.Microsoft.Extensions.Caching.StackExchangeRedis. This issue covers logs only;KEYS/SCANoutput and RDB snapshots still contain them, which is documented indocs/reference/settings.md.Interim state
#121 documents the exposure in
docs/reference/settings.mdunderCaching:Distributedso an operator can scope log access or filter theUiPath.Cachingcategories until this lands.