CVE-2026-57527: Verified Reproduction
CVE-2026-57527: ZAP ViewState add-on insecure deserialization RCE
CVE-2026-57527 is verified against zaproxy/zap-extensions · github. Affected versions: ViewState add-on versions 1, 2, and 3 (before version 4). Fixed in ViewState add-on version 4. Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00249.
What Is CVE-2026-57527?
CVE-2026-57527 is a high-severity insecure deserialization vulnerability in the Zed Attack Proxy (ZAP) ViewState add-on (versions 1-3, before version 4), where a malicious proxied web server can trigger arbitrary code execution inside the ZAP process. Pruva reproduced it (reproduction REPRO-2026-00249).
CVE-2026-57527 Severity & CVSS Score
CVE-2026-57527 is rated high severity, with a CVSS base score of 8.8 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
Affected zaproxy/zap-extensions Versions
zaproxy/zap-extensions · github versions ViewState add-on versions 1, 2, and 3 (before version 4) are affected.
How to Reproduce CVE-2026-57527
pruva-verify REPRO-2026-00249 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00249/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-57527
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
Base64 Java serialized object in javax.faces.ViewState field served by malicious TCP HTTP peer
- TCP HTTP response
- ZAP HttpMessage
- ViewState response panel
- ViewStateModel
- JSFViewState.decode
- ObjectInputStream.readObject
reproduction_steps.sh How the agent worked
Root Cause and Exploit Chain for CVE-2026-57527
CVE-2026-57527 affects the ZAP ViewState add-on before the fix in commit ac6c3f94d38505bc0facea286a4d3728044c6e5c. The add-on's response ViewState panel registered the JSF parameter name javax.faces.ViewState; when a proxied HTTP response contained that hidden field, the original ZAP add-on path created a JSFViewState and decoded it with Java ObjectInputStream.readObject() without a deserialization filter or type allowlist. A malicious web server controlling a response viewed/proxied through ZAP can therefore supply a Base64-encoded serialized Java object that is deserialized inside the ZAP JVM. The current reproduction confirms arbitrary command execution through the actual built ZAP ViewState add-on component path, not a reimplemented handler.
- Package/component affected:
zap-extensions, add-onaddOns/viewstate/ ZAP ViewState add-on. - Affected versions: ViewState add-on versions before version 4 / before fixed commit
ac6c3f94d38505bc0facea286a4d3728044c6e5c. The verified vulnerable checkout is the fixed commit parent7e686c0900e82bb73b57880c0328d012269f8741. - Risk level and consequences: High. An attacker-controlled proxied web server can return an HTML response containing a malicious
javax.faces.ViewStatevalue. When the vulnerable ZAP ViewState add-on response panel processes that response, attacker-controlled Java deserialization occurs in the ZAP process and can execute commands with the privileges of the ZAP user.
Impact Parity
- Disclosed/claimed maximum impact: Arbitrary code execution / RCE through ZAP processing a proxied malicious ViewState response.
- Reproduced impact from this run: Code execution. The payload's
readObject()ran/bin/sh -c "id > ...; echo RCE_VIA_ZAP_VIEWSTATE_PRODUCT_PATH >> ..."inside the deserializing JVM, producing marker files and command output. - Parity:
full. - Not demonstrated: A full desktop browser GUI session was not used. Instead, the proof builds the actual vulnerable and fixed
.zapadd-on archives and drives the original response-panel product component boundary with a real ZAPHttpMessagepopulated from bytes read across a TCP socket. This reaches the original ZAP add-on path (ExtensionHttpPanelViewStateView$ResponseSplitBodyViewStateViewFactory -> HttpPanelViewStateView -> ViewStateModel -> JSFViewState.decode) and demonstrates the claimed code-execution impact.
Root Cause
The vulnerable ViewStateModel registered JSF ViewState fields as parseable ViewState parameters:
viewstateParams.add(new ViewState(null, JSFViewState.KEY, "javax.faces.ViewState"));
For response bodies, ViewStateModel.getData() calls getViewStateParam() on the HTTP response body. If javax.faces.ViewState is found, getViewStateParam() constructs a JSFViewState object. ViewState.getDecodedValue() then calls JSFViewState.decode(), whose vulnerable implementation Base64-decodes the supplied value and passes it directly to ObjectInputStream.readObject():
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
Because the serialized stream is attacker-controlled and no Java serialization filter, class allowlist, or safe parser is used, a gadget or attacker-defined serializable class available to the deserializing JVM can execute code during readObject().
The known fix is commit ac6c3f94d38505bc0facea286a4d3728044c6e5c (https://github.com/zaproxy/zap-extensions/commit/ac6c3f94d38505bc0facea286a4d3728044c6e5c), which disables the JSF ViewState registration in ViewStateModel:
// viewstateParams.add(new ViewState(null, JSFViewState.KEY, "javax.faces.ViewState"));
With that change, the fixed add-on does not create JSFViewState for the same response field and therefore does not reach JSFViewState.decode() for the malicious input.
Reproduction Steps
- Use
bundle/repro/reproduction_steps.sh. - The script:
- Locates the prepared
zap-extensionsrepository frombundle/project_cache_context.jsonor clones a fallback checkout. - Resolves the fixed commit
ac6c3f94d38505bc0facea286a4d3728044c6e5cand vulnerable parent7e686c0900e82bb73b57880c0328d012269f8741. - Creates clean worktrees for both versions and verifies the JSF registration is active in the vulnerable checkout and commented out in the fixed checkout.
- Builds the actual ViewState add-on
.zaparchive from each checkout with Gradle task:addOns:viewstate:jarZapAddOn. - Starts a real malicious TCP HTTP server that serves an HTML page with a hidden
javax.faces.ViewStatefield containing a Base64 serialized Java object. - Runs a Java product-component harness that reads the malicious HTTP response from the TCP socket, creates a real ZAP
HttpMessage, instantiates the originalExtensionHttpPanelViewStateView$ResponseSplitBodyViewStateViewFactory, obtains the originalHttpPanelViewStateView, and triggers the normalHttpPanelViewModel.setMessage(HttpMessage)listener path. - Performs two vulnerable attempts and two fixed negative-control attempts.
- Locates the prepared
- Expected evidence:
- Vulnerable attempts log that
ViewStateModelandHttpPanelViewStateViewwere loaded from the vulnerable built.zap, showViewStateModel.has_jsf_registration=true, and createvuln_marker_1.txt/vuln_marker_2.txtplusvuln_rce_output_1.txt/vuln_rce_output_2.txt. - The marker stack traces include
JSFViewState.decode,ViewStateModel.getData,HttpPanelViewStateView.dataChanged, andDefaultHttpPanelViewModel.setMessage. - Fixed attempts log that classes were loaded from the fixed built
.zap, showViewStateModel.has_jsf_registration=false, and do not create marker/RCE files.
- Vulnerable attempts log that
Evidence
Primary evidence files:
bundle/repro/reproduction_steps.sh— verified twice consecutively.bundle/repro/runtime_manifest.json— runtime manifest withentrypoint_kind="tcp_peer",service_started=true,healthcheck_passed=true, andtarget_path_reached=true.bundle/logs/reproduction_steps.log— full build and runtime transcript.bundle/logs/vuln_harness_1.log,bundle/logs/vuln_harness_2.log— vulnerable product-path harness logs.bundle/logs/fixed_harness_1.log,bundle/logs/fixed_harness_2.log— fixed negative-control harness logs.bundle/logs/server_vuln_1.log,bundle/logs/server_vuln_2.log,bundle/logs/server_fixed_1.log,bundle/logs/server_fixed_2.log— malicious TCP server logs proving accepted HTTP connections.bundle/repro/artifacts/vuln_marker_1.txt,bundle/repro/artifacts/vuln_marker_2.txt— deserialization marker files containing stack traces.bundle/repro/artifacts/vuln_rce_output_1.txt,bundle/repro/artifacts/vuln_rce_output_2.txt— command output files.bundle/repro/artifacts/source_identity.txt— vulnerable/fixed commit IDs and SHA-256 hashes of the built.zaparchives.bundle/repro/artifacts/fix.patch— patch diff for the ViewState add-on.
Key excerpts from the successful run:
[setup] Vulnerable commit (fixed parent): 7e686c0900e82bb73b57880c0328d012269f8741
[setup] Fixed commit: ac6c3f94d38505bc0facea286a4d3728044c6e5c
[verify] Vulnerable ViewStateModel JSF registration:
... ViewStateModel.java:62: viewstateParams.add(new ViewState(null, JSFViewState.KEY, "javax.faces.ViewState"));
[verify] Fixed ViewStateModel JSF registration is disabled:
... ViewStateModel.java:62: // viewstateParams.add(new ViewState(null, JSFViewState.KEY, "javax.faces.ViewState"));
The vulnerable runtime path loaded the actual vulnerable add-on and saw the JSF registration:
[vuln-1] view_loaded_from=file:.../worktrees/vulnerable/addOns/viewstate/build/zapAddOn/bin/viewstate-alpha-4.zap
ViewStateModel.loaded_from=file:.../worktrees/vulnerable/addOns/viewstate/build/zapAddOn/bin/viewstate-alpha-4.zap
ViewStateModel.param name=javax.faces.ViewState type=JSF
ViewStateModel.has_jsf_registration=true
[vuln-1] invoking real HttpPanelViewModel.setMessage(HttpMessage)
[vuln-1] marker_exists=true
[vuln-1] rce_output_exists=true
The RCE marker confirms deserialization and shows the original ZAP add-on call stack:
DESERIALIZATION_RCE_CONFIRMED
command=id > '.../vuln_rce_output_1.txt'; echo RCE_VIA_ZAP_VIEWSTATE_PRODUCT_PATH >> '.../vuln_rce_output_1.txt'
...
at org.zaproxy.zap.extension.viewstate.zap.utils.JSFViewState.decode(JSFViewState.java:92)
at org.zaproxy.zap.extension.viewstate.zap.utils.JSFViewState.decode(JSFViewState.java:76)
at org.zaproxy.zap.extension.viewstate.zap.utils.ViewState.getDecodedValue(ViewState.java:64)
at org.zaproxy.zap.extension.viewstate.ViewStateModel.getData(ViewStateModel.java:183)
at org.zaproxy.zap.extension.viewstate.HttpPanelViewStateView.dataChanged(HttpPanelViewStateView.java:189)
at org.zaproxy.zap.extension.httppanel.view.DefaultHttpPanelViewModel.setMessage(DefaultHttpPanelViewModel.java:42)
The command output proves attacker-controlled code ran in the deserializing JVM:
uid=1000(vscode) gid=1000(vscode) groups=1000(vscode),969(969)
RCE_VIA_ZAP_VIEWSTATE_PRODUCT_PATH
The fixed negative controls process the same malicious response through the fixed built add-on but do not deserialize it:
[fixed-1] view_loaded_from=file:.../worktrees/fixed/addOns/viewstate/build/zapAddOn/bin/viewstate-alpha-4.zap
ViewStateModel.param_count=2
ViewStateModel.param name=__VIEWSTATE type=ASP
ViewStateModel.param name=__VIEWSTATEFIELDCOUNT type=ASP
ViewStateModel.has_jsf_registration=false
[fixed-1] marker_exists=false
[fixed-1] rce_output_exists=false
Environment details captured by the script include OpenJDK version, exact commits, built archive paths, SHA-256 hashes, TCP server logs, and runtime manifest metadata.
Recommendations / Next Steps
- Keep the JSF ViewState parser disabled unless it is replaced with a safe, non-deserializing parser.
- If JSF ViewState support is restored, do not call unrestricted
ObjectInputStream.readObject()on data from HTTP responses. Use a strictly bounded parser or, at minimum, a JEP 290ObjectInputFilterwith a tight allowlist and resource limits. - Release and deploy ViewState add-on version 4 or later containing commit
ac6c3f94d38505bc0facea286a4d3728044c6e5c. - Add regression tests that feed a serialized-object-looking
javax.faces.ViewStateresponse through the actual response-panel model path and assert thatJSFViewState.decode()/ObjectInputStream.readObject()is not reached. - Consider auditing other add-ons for Java deserialization of proxied request/response data.
Additional Notes
- Idempotency confirmed:
bundle/repro/reproduction_steps.shwas run twice consecutively and passed both times. - The proof uses a headless product-component boundary rather than launching the full Swing desktop. It still loads the actual built
.zapadd-on classes and drives the original response-panel listener/model path with a real ZAPHttpMessagecreated from bytes received across a TCP socket. - The harness only initializes minimal Swing/I18N state needed for headless execution; it does not reimplement ViewState selection or toggle the fix. The vulnerable/fixed comparison is produced by building and loading different add-on archives from the vulnerable and fixed commits.
- No sanitizer was used; the observed impact is real Java command execution during deserialization.
CVE-2026-57527 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
ls -la /data/pruva/project-cache/a032c641-95cb-4a13-867e-d136b678d029/repo-mirrors/ 2>/dev/null; echo "---"; cat /data/pruva/project-cache/a032c641-95cb-4a13-867e-d136b678d029/repo-mirrors/*.txt 2>/dev/null; echo "---check repo dirs---"; find /data/pruva/project-cache/a032c641-95cb-4a13-867e-d136b678d029 -maxdepth 2 -type d 2>/dev/nulltotal 0 drwxr-xr-x 1 vscode vscode 0 Jul 5 07:06 . drwxr-xr-x 1 vscode vscode 24 Jul 5 07:06 .. --- ---check repo dirs--- /data/pruva/project-cache/a032c641-95cb-4a13-867e-d136b678d029 /data/pruva/project-cache/a032c641-95cb-4a13-867e-d136b678d029/repo-mirrors
Artifacts and Evidence for CVE-2026-57527
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-57527
Upgrade zaproxy/zap-extensions · github to ViewState add-on version 4 or later.
FAQ: CVE-2026-57527
How does the CVE-2026-57527 ViewState deserialization attack work?
Which versions of the ZAP ViewState add-on are affected by CVE-2026-57527, and where is it fixed?
How severe is CVE-2026-57527?
How can I reproduce CVE-2026-57527?
References for CVE-2026-57527
Authoritative sources for CVE-2026-57527 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.