GHSA-FP43-VJ7G-PG92: Root-Cause Fixes Across OmniFaces Resource, XSS, and WebSocket Paths
Summary
OmniFaces 2.7.33 addresses four distinct security issues with targeted code changes and regression tests: forged combined-resource identifiers are constrained to combinable asset types and no longer poison cache state; URL-safe inflation is bounded to prevent decompression-driven memory exhaustion; o:hashParam output is JavaScript-escaped to block script breakout; and WebSocket handling now binds non-application channels to the originating HTTP session while adding configurable idle timeout and per-channel session caps. The patch set is largely root-cause oriented because it tightens trust boundaries at decode, render, and handshake layers rather than only filtering specific payloads.
Analysis
Vulnerability
GHSA-FP43-VJ7G-PG92 describes a multi-vector issue in OmniFaces versions before 2.7.33. The affected areas are independent but share the same pattern: attacker-controlled input crossed trust boundaries without sufficient validation.
First, combined resource identifiers could be forged so that the resource handler resolved arbitrary resource names instead of only server-issued bundles. The patch summary and tests show the intended security boundary is that only stylesheet and script resources are combinable, and forged identifiers must not be retained in cache state. Second, URL-safe deserialization used inflation without an upper bound, enabling a compressed payload to expand into excessive memory consumption. Third, o:hashParam embedded unescaped values into a JavaScript callback, allowing payloads to break out of string context or surrounding markup context. Fourth, WebSocket channels for session/view scope were not sufficiently tied to the owning HTTP session, enabling unauthorized handshakes, while unlimited idle lifetime and unbounded concurrent sessions increased abuse potential.
// Vulnerable patterns from the supplied diffs
return new String(toByteArray(new InflaterInputStream(deflated)), UTF_8);
return format(SCRIPT_UPDATE, getName(), getRenderedValue(context));
session.setMaxIdleTimeout(0);
These issues are evidenced by the supplied commits for combined resource handling and inflation control (aa42da3), XSS hardening in HashParam (c43eef0), WebSocket handshake/session controls (d5cae24), and regression tests for forged combined-resource IDs (59d6c51).
Patch
The combined-resource fix in aa42da3 changes CombinedResourceInfo so cache insertion only occurs for combinable resource identifiers and introduces isCombinable() to enforce a strict allowlist based on .css and .js suffixes. The same change path also avoids cache growth from forged IDs by only caching canonical server-side combinations. The associated test commit 59d6c51 verifies rejection of malformed IDs, non-combinable resources, inflation bombs, and cache retention of forged IDs.
The memory exhaustion fix in aa42da3 replaces unbounded inflation with a streaming read capped by MAX_UNSERIALIZED_LENGTH = 64 * 1024. This is a direct mitigation against decompression bombs in the URL-safe unserialization path.
The XSS fix in c43eef0 wraps both the hash parameter name and rendered value with escapeJS(..., true) before formatting the callback script. The added integration test explicitly covers single-quote breakout and CDATA-closing payloads.
The WebSocket fix in d5cae24 introduces a custom endpoint configurator that rejects handshakes for non-application-scoped channels unless the channel ID was registered in the current HTTP session. It also adds configurable endpoint idle timeout and a configurable maximum number of concurrent sessions per channel, enforced in session management.
private static boolean isCombinable(Set<ResourceIdentifier> resourceIdentifiers) {
for (ResourceIdentifier resourceIdentifier : resourceIdentifiers) {
String name = resourceIdentifier.getName();
if (name == null) {
return false;
}
String lowerCaseName = name.toLowerCase();
if (!lowerCaseName.endsWith(CombinedResourceHandler.EXTENSION_CSS)
&& !lowerCaseName.endsWith(CombinedResourceHandler.EXTENSION_JS)) {
return false;
}
}
return true;
}
while ((read = inflater.read(buffer)) != -1) {
inflated.write(buffer, 0, read);
if (inflated.size() > MAX_UNSERIALIZED_LENGTH) {
throw new IllegalArgumentException("Unserialized data exceeds maximum allowed length of " + MAX_UNSERIALIZED_LENGTH + " bytes.");
}
}
return format(SCRIPT_UPDATE, escapeJS(getName(), true), escapeJS(getRenderedValue(context), true));
if (!SocketChannelManager.isApplicationScopedChannelId(channelId)
&& !SocketChannelManager.isChannelIdRegisteredInSession((HttpSession) request.getHttpSession(), channelId)) {
throw new IllegalStateException(ERROR_UNAUTHORIZED_CHANNEL);
}
Review
Pros
- The resource-handler changes address trust at the object model boundary, not just at presentation time. Restricting combined resources to CSS/JS is aligned with the feature's intended domain and blocks arbitrary resource resolution at source.
- The forged-ID cache behavior is improved: structurally valid but attacker-supplied IDs can be served when safe, yet are not persisted into cache state. This reduces memory amplification and cache pollution risk, as validated by the regression test in 59d6c51.
- The inflation cap is a strong root-cause mitigation for decompression abuse. Streaming with an explicit byte ceiling is materially safer than inflating to completion and only then allocating the resulting string.
- The
HashParamfix escapes both the parameter name and value, which is important because either field can become a script sink when interpolated intoformat(SCRIPT_UPDATE,...). The added test cases are realistic and directly tied to the vulnerable rendering pattern in c43eef0. - The WebSocket configurator is a meaningful authorization improvement. Binding session/view-scoped channels to the originating HTTP session closes the handshake gap instead of relying on downstream behavior after connection establishment.
- Operational hardening was added alongside the authorization fix: configurable idle timeout and per-channel session caps reduce resource retention and connection-flood impact.
Cons
- The combinable-resource allowlist is extension-based. That is appropriate for this feature, but it assumes suffixes are a sufficient proxy for safe resource classes. If the framework can expose dynamic or sensitive resources under
.jsor.cssnames, this check would not fully model authorization semantics. - The 64 KiB inflation ceiling is a pragmatic limit, but the patch excerpt does not show whether all callers can safely handle
IllegalArgumentExceptionwithout noisy error paths or log amplification. The test confirms rejection, not end-to-end failure handling. - The WebSocket max-session cap is enforced at
onOpen, and the included test notes that the second handshake still returns 101 before immediate closure. This is acceptable for limiting steady-state abuse, but it does not fully prevent handshake-rate pressure. - The session-binding logic depends on channel registration in HTTP session state. The patch excerpt does not show cleanup semantics for stale registered channel IDs across session lifecycle events, though that is more of a hygiene concern than a bypass in the supplied evidence.
Verdict
Root-cause.
The patch set is predominantly root-cause oriented across all four vectors. For combined resources, it narrows accepted identifiers to the intended asset class and prevents forged IDs from becoming durable cache entries. For memory exhaustion, it adds a hard upper bound during inflation rather than trying to detect specific malicious payload shapes. For XSS, it fixes the actual script sink by escaping interpolated values before rendering. For WebSockets, it moves authorization into the handshake path by verifying that non-application channels belong to the current HTTP session. The remaining caveats are mostly design tradeoffs and operational details, not evidence of a superficial bandaid.
Engineers upgrading should still regression-test any application behavior that depends on large serialized payloads, custom resource naming conventions, or high fan-out WebSocket usage, and should review the new socket context parameters introduced in d5cae24. Overall, 2.7.33 appears to be the correct remediation target per the advisory at GitHub Security Advisory and the referenced patch series.
Recommended Labs
Try this vulnerability pattern yourself with hands-on labs.
- XSS.java
Best direct match for the OmniFaces advisory because the issue set explicitly includes XSS in a Java web stack. This hands-on lab focuses on finding and fixing server-side cross-site scripting patterns relevant to JSF-style output handling and request-driven rendering.
- Cookie.js
A strong defensive companion lab for the advisory’s WebSocket hijacking angle. While not WebSocket-specific, it trains browser-side session protection using HttpOnly cookie hardening, which is directly relevant to reducing token or session theft impact in browser-mediated attacks.
- No Sutpo.java
Useful for the arbitrary resource access / authorization side of the advisory. This Java lab develops hands-on defensive skills around broken authorization and horizontal privilege issues, which maps well to preventing unintended resource exposure in server-side frameworks.