CVE-2026-102695 is a high-severity (CVSS 8.2) CWE-345 vulnerability in org.omnifaces:omnifaces. A fix is available for org.omnifaces:omnifaces — see the affected versions and patch details below.
OmniFaces: Forged combined-resource IDs and related output/push boundaries
Exploitation Status
No confirmed exploitation observed yet
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-102695.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
CVE-2026-102695 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.
Where this sits among everything scored
Of 394,803 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.
Real-World Exposure
org.omnifaces:omnifaces☕org.omnifaces:omnifaces☕org.omnifaces:omnifaces☕org.omnifaces:omnifaces☕org.omnifaces:omnifacesReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Maven packages — download data is not available via public APIs for these ecosystems.
Description
1. Forged combined-resource IDs
CombinedResourceInfo accepts a path-derived ID without an authenticity check,
inflates it without an output limit, converts it to attacker-selected resource
identifiers, and retains unique IDs in an unbounded static cache. In bounded
tests, 20,754 encoded bytes inflated to 16,000,000 characters (about 770:1;
about 49 MB observed heap delta), and 200 unique IDs added 200 permanent cache
entries. A legitimately shaped short ID remained about 1:1, while malformed
input was rejected; the missing distinction is between a server-issued ID and
an attacker-minted but structurally valid ID.
The minimal application also confirmed three sink tails from the same forged-ID root:
- A wildcard CDN mapping performed a server-side fetch and relayed the exact loopback-canary body. This requires the documented combined-resource and wildcard-CDN configuration.
- A forged inner
.xhtmlresource bypassed the excluded-resource boundary and returned its raw content. - A forged
omnifaces.graphicinner resource plus a canaryHostheader caused an outbound GET to that host. This result is blind and deployment-dependent; I am not claiming arbitrary-scheme or arbitrary-destination SSRF.
These behaviors reproduce after the fix for CVE-2026-41883 / GHSA-vp6r-9m58-5xv8. That advisory concerned EL evaluation order in the wildcard CDN path. This report has a different root: unsigned combined IDs and missing decode/cache bounds, with separately demonstrated residual sink behavior.
2. Source-map cache
With the documented optional source-map handler above a synthetic resource handler, 40 unique missing combined-resource requests grew the process-wide source-map cache from 13 to 92 entries. It has no size or eviction bound. This has a separate cache, configuration prerequisite, and fix from family 1.
3. HashParam callback output
A URL-fragment value containing a single-quote JavaScript payload was stored by
o:hashParam and later written unescaped into the Ajax callback script. On the
follow-up Ajax render, real Chrome executed the canary
window.__omniXss=1337. This requires a page using o:hashParam and the
follow-up Ajax render.
4. Session/view push-channel replay
A fresh WebSocket client with no HTTP cookie connected using a victim's session-scoped channel ID and received the victim's subsequent push. The code checks application-wide ID existence but does not bind the handshake to the current HTTP session, despite the documented current-session guarantee. The UUID remains an unguessable bearer-token prerequisite; this is replay after token exposure, not brute force.
5. Push idle-connection and fanout behavior
Twelve independent clients joined one application-scoped channel and all 12 received the same push. Current code sets every accepted session's maximum idle timeout to zero, retains sessions in an unbounded per-channel queue, and walks the full queue on each push. I am reporting the demonstrated mechanism as a bounded design weakness: container connection limits remain an outer bound, and I am not claiming unbounded heap growth from the 12-client test.
Intentionally excluded leads
- A duplicate-Range response-amplification lead was disproved. Twenty-four ranges produced only one response body because the stream wrapper closes after the first range. I am not reporting it as a security issue.
- The older
Servlets.facesRedirectXML issue is fixed on the current branch. I am not reporting it as a new current-upstream issue.
Expected invariants
- Only server-issued combined IDs should be accepted; decoding and caches should be bounded; excluded resources and dynamic handlers should not become attacker-selected inner resources.
- Dynamic URLs should not derive an outbound destination from an untrusted
Hostheader. - Source-map lookups should not create unbounded process-lifetime state.
HashParamvalues must be escaped for a JavaScript string inside an XML CDATA callback.- Session/view push subscriptions should be bound to the owning HTTP session or authenticated principal; idle limits and per-channel caps should remain operator-controllable.
Suggested fixes and available evidence
- Authenticate generated combined IDs with a per-deployment secret, cap inflated output, bound the combined cache, and avoid caching failed loads.
- Require an existing/registered inner resource before wildcard remapping and reject excluded resource types at serve time.
- Derive dynamic-resource origins from trusted configuration rather than the
request
Hostvalue. - Bound or evict the source-map cache.
- Apply JavaScript-string plus CDATA-safe encoding to
HashParamcallback values. - Capture and verify HTTP-session or principal ownership during the WebSocket handshake; retain a finite idle timeout and configurable per-channel limits.
Daniel Birtwhistle
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| ☕Maven | org.omnifaces:omnifaces | all versions | 1.14.3org.omnifaces:omnifaces:1.14.3 |
| ☕Maven | org.omnifaces:omnifaces | ≥ 2.0.0&&< 2.7.33 | 2.7.33org.omnifaces:omnifaces:2.7.33 |
| ☕Maven | org.omnifaces:omnifaces | ≥ 3.0.0&&< 3.14.23 | 3.14.23org.omnifaces:omnifaces:3.14.23 |
| ☕Maven | org.omnifaces:omnifaces | ≥ 4.0.0&&< 4.7.12 | 4.7.12org.omnifaces:omnifaces:4.7.12 |
| ☕Maven | org.omnifaces:omnifaces | ≥ 5.0.0&&< 5.4.2 | 5.4.2org.omnifaces:omnifaces:5.4.2 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for org.omnifaces:omnifaces, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update org.omnifaces:omnifaces to 1.14.3 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-102695 is resolved across your whole dependency graph.
Workarounds
Restrict outbound requests from the affected component to an allowlist of hosts, block access to link-local and internal address ranges at the network layer, and require authentication on internal services so a forged request cannot reach them unauthenticated.
Frequently Asked Questions
Is CVE-2026-102695 in your dependencies?
Find it across Maven, including transitive dependencies.