رأس القلم

CVE-2026-47890: Spring SSE Stream Corruption and Fixes

CVE-2026-47890 affects a specific Spring rendering path: view fragments sent over Server-Sent Events, with attacker-controlled content reaching another user. Spring’s advisory rates the issue Low. It describes stream corruption that can affect displayed information or client state, depending on frontend behavior. This is not a general Spring remote-code-execution advisory.

A useful assessment follows the data from its author to the event stream and then to the receiving browser. Finding a Spring dependency is an inventory result. Establishing that a lower-trust author can influence another user’s rendered stream is an application-specific exposure result. Keep those conclusions separate when triaging scanner alerts.

Affected versions and the supported fix route

Framework lineAffected rangeAdvisory-listed correction
7.07.0.0–7.0.87.0.9 OSS; 7.0.8.1 Enterprise Support Only
6.26.2.0–6.2.196.2.20 Enterprise Support Only
Release scope and availability from the linked Spring advisory.

إن vendor remediation table distinguishes publicly available and enterprise fixes; do not assume every listed artifact is available from a public repository. Select a maintained, compatible release that includes the correction. For a dependency-managed application, verify the resolved Framework artifacts rather than inferring the result from a parent project’s version string.

Why an event stream needs its own boundary

Spring’s HTML fragment documentation describes sending rendered fragments through SSE, including ModelAndView values passed through SseEmitter. This differs from returning one complete HTML page. Content passes through view rendering, event serialization, transport, and client event handling before it reaches the displayed interface.

إن HTML Standard’s SSE parsing rules define a line-oriented format. Multiple data fields can contribute to one event, and an empty line dispatches the accumulated event. Those separators belong to the transport grammar. An application needs content to remain data inside that grammar, even when a rendered fragment contains legitimate line breaks.

HTML escaping and event framing protect different boundaries. Escaping a fragment for its intended HTML context does not, by itself, demonstrate that its serialized event boundaries remain intact. Conversely, preserving event boundaries does not establish that every HTML insertion operation is safe. Review the output at both stages instead of treating one successful encoding check as proof of the other.

This is a protocol-level explanation, not a reconstruction of Spring’s patch. The advisory establishes the affected feature combination and potential effect. It does not justify labeling every streaming endpoint vulnerable or asserting an application-specific execution path without testing that path.

Conceptual flow from lower-trust model data through HTML rendering and SSE framing to browser state
Conceptual trust boundary; this diagram does not reconstruct an exploit or the vendor patch.

A local framing exercise with harmless text

The following standard-library example illustrates the difference between one event containing two data lines and two separate events. It makes no network requests, uses no Spring application, and contains no exploit payload. It is a small teaching model, not a standards-complete parser or a CVE detector.

def messages(wire):
    result, data = [], []
    for line in wire.splitlines():
        if line == "":
            if data:
                result.append("\n".join(data))
            data = []
        elif line.startswith("data:"):
            value = line[5:]
            data.append(value[1:] if value.startswith(" ") else value)
    return result

one_event = "data: alpha\ndata: beta\n\n"
two_events = "data: alpha\n\ndata: beta\n\n"

assert messages(one_event) == ["alpha\nbeta"]
assert messages(two_events) == ["alpha", "beta"]
print("The event boundary changes the parsed result.")

An application regression test should exercise the actual framework serializer and browser consumer. The toy example cannot establish whether a Spring build is affected, whether a rendered fragment is attacker-controlled, or what a client does with the resulting event. Its purpose is to make the acceptance condition precise: intended content must not unexpectedly change the event structure.

Find the relevant path in an owned codebase

Start with dependency resolution and then inspect the rendering route. In an owned checkout, search for text/event-stream, SseEmitter, ModelAndView, and the code that passes model values into rendered views. These are review leads, not signatures. A plain JSON event publisher and an SSE view-fragment renderer may share an output MIME type while using different application paths.

For each candidate route, identify the content author and recipient. Is the value fixed by the application, editable only by administrators, or supplied by a less-trusted user? Is it sent only back to its author or broadcast to other sessions? Trace the actual template and event-construction code. A shared database table alone does not prove that the relevant field reaches the stream.

Then inspect the receiving logic. Record the event type, destination element, state update, and any follow-up action. Use synthetic records and separate test accounts in an owned staging environment. Establish the intended cross-user behavior before checking unexpected behavior; otherwise a deliberately shared notification can be mistaken for an authorization defect.

Build a regression record around observable results

Recommended caseWhat to observeLimit of the result
Normal fragmentExpected event count and correct displayed contentDoes not exercise multiline content
Multiline synthetic contentContent remains within intended event boundariesUse the real renderer and serializer
Two dedicated recipientsOnly intended sessions receive the updateDelivery authorization is a separate property
Patched deploymentResolved artifacts, rebuilt image, and repeated casesA build log alone does not prove rollout

Retain a short event-stream capture alongside the browser observation. Sanitize credentials and use harmless markers instead of customer content. Compare event count, event type, parsed data, and visible state with the expected result. HTTP 200 proves neither correct framing nor a correct client update.

If unexpected boundaries appear, first separate renderer behavior from proxy buffering and client handling. Preserve the raw response and the test input. Report only the demonstrated consequence: an extra event, altered displayed text, or an incorrect state transition. A presentation defect does not automatically establish arbitrary JavaScript execution, data theft, or server compromise.

Complete the update in the deployed application

Rebuild and deploy the application with the reviewed dependency set, then verify which artifacts reached the running service. Repeat the same synthetic cases and a normal fragment update. For a rolling deployment, check more than one instance when the routing allows old and new builds to serve concurrently. Record the application release and Framework versions together.

Close the finding with evidence for the relevant feature path and its correction. If the application does not send view fragments through SSE, document how that conclusion was reached and retain the dependency inventory separately. That gives the next reviewer a reasoned scope decision rather than a blanket claim that every Spring application is safe or exposed.

Recommended dependency resolution, path review, deployment and controlled regression workflow
Recommended verification workflow; this is not a record of a production test.
شارك المنشور:
منشورات ذات صلة
arArabic