Overview
About vulnerability
Summary
UnwrappedPropertyHandler.processUnwrapped() replays the buffered JSON for a @JsonUnwrapped property by iterating its properties and calling prop.deserializeAndSet() with no prop.visibleInView(ctxt.getActiveView()) guard — the exact guard processUnwrappedCreatorProperties() received in the #5971 / GHSA-rcqc-6cw3-h962 fix, and the guard BeanDeserializer.deserializeWithUnwrapped applies to directly-matched properties. As a result, a property annotated with both @JsonView(PrivilegedView.class) and @JsonUnwrapped is written from attacker JSON even when deserializing under a more-restrictive active view.
Correction to the original framing (runtime-verified): the gap is NOT a per-field inner @JsonView (the unwrapped sub-object’s own BeanDeserializer gates inner fields correctly). The unchecked gate is the view of the unwrapped CONTAINER property.
Intent proof (runtime, 2.x HEAD 21dd70dd and 3.x HEAD 7a5939d6)
An @JsonView(AdminView) property that is NOT @JsonUnwrapped → null under PublicView (correctly gated). The identical property WITH @JsonUnwrapped → fully populated (bypass). The fix the creator path already received, not applied to the regular-property method.
Impact — write-side mass-assignment / privilege escalation
@JsonView is commonly used as a write-side authorization guard: a public endpoint binds the body under readerWithView(PublicView.class) and groups privileged state in a nested object whose container property is @JsonView(AdminView). When that property is @JsonUnwrapped, an untrusted caller mass-assigns it. PoC: a self-service registration where AccountFlags{role,approved,creditBalance} is @JsonView(AdminView) @JsonUnwrapped; attacker JSON {role:ADMIN,approved:true,creditBalance:1000000} under PublicView binds all three → approved admin with arbitrary balance. The failing gate is a WRITE gate, hence integrity-high (C:N/I:H/A:N); no worse than the C:L/I:L parent and arguably higher as @JsonView-as-write-guard is the exact use case #5971/#5969 defended.
Affected
com.fasterxml.jackson.core:jackson-databind2.x: confirmed bypass at 21dd70dd (== released 2.21.4 / 2.22.0 line; includes the #5973 backport).DEFAULT_VIEW_INCLUSIONdefault=true.tools.jackson.core:jackson-databind3.x: confirmed bypass at HEAD 7a5939d6 (latest 3.x).DEFAULT_VIEW_INCLUSIONdefault=false → the stock-config repro is the common shape where privileged inner fields are individually@JsonView(PublicView)and the developer relies on the container@JsonView(AdminView); the 3.x PoC mass-assigns role/approved/creditBalance under PublicView. (The other simultaneous report’s PoC was reportedly fixed on 3.x; this distinct container-property path is not.)
Additive variants (runtime-confirmed both branches; all closed by the same one-line guard)
- nested
@JsonUnwrapped(unwrapped-in-unwrapped) — recursive bypass. - merge /
readerWithView(...).withValueToUpdate(...)(PATCH/partial-update) — bypass; non-unwrapped merge control gates correctly. - builder-based deserializer (
@JsonDeserialize(builder=...)) —BuilderBasedDeserializerroutes through the sameprocessUnwrapped. - Honest non-findings: read-side serialization correctly honors views (no leak);
@JsonAnySetter+view and@JsonTypeInfo+@JsonUnwrappedare separate/unsupported behaviors, not this bug.
Fix
Add prop.visibleInView(ctxt.getActiveView()) (when MapperFeature.DEFAULT_VIEW_INCLUSION/active-view applies) to the processUnwrapped() property loop, mirroring processUnwrappedCreatorProperties(). One change closes the impact PoC + all three variants across BeanDeserializer and BuilderBasedDeserializer. Full runnable PoCs (2.x + 3.x) + variant harnesses available on request.
Details
- Affected product:
- Apache CXF , Apache Hadoop , Apache Hive , Apache Kafka , Apache Log4j , Apache Maven , Apache Solr , Apache Spark , Apache Struts , Elasticsearch , Gradle , Hazelcast , Hibernate , Jackson , OpenSearch , Spring , Wildfly , accumulo , activemq , agepredictor , archaius , artemis , avro , aws-java-sdk-xray , aws-sdk-java , aws-xray-sdk-java , azure-sdk-for-java , azure-spring-data-cosmos , bookkeeper , bookkeeper-common-allocator , calcite , camel , cassandra-java-driver , com.wavefront:wavefront-sdk-java , consul-client , corda , couchbase-jvm-clients , couchbase-jvm-clients-core-io , couchbase-jvm-clients-java-client , debezium , distributedlog , docker-java , docx4j , droolsjbpm-integration , etcd4j , eureka , flink , grails-core , grails-data-mapping , grails-gsp , grails-plugin-converters , graphql-java-servlet , groovy , hbase , http-client , hystrix , incubator-retired-htrace , infinispan , jasperreports , java-apns , java-cas-client , java-driver , java-genai , java-jwt , java-opensaml , jersey , jgroups-aws , jjwt , json-patch , json-schema-core , json-schema-validator , jsonpath , jsonschema-generator , karaf , kubernetes-client , logging-flume , micrometer , micrometer-tracing , micronaut-cache , micronaut-core , micronaut-spring , neo4j-ogm , olingo-odata4 , openstack4j , org.apache.groovy:groovy-all , parquet-java , pinecone-java-client , pulsar , pulsar-client-reactive , redisson , rescu , rest-assured , resteasy , ribbon , signalfx-java , smallrye-open-api , swagger-core , swagger-parser , testcontainers-java , tika , tinkerpop , trendrrnsqclient , twilio-java , typesense-java , vert.x , wavefront-internal-reporter-java , web3j , wiremock , ws-wss4j , xchange , zendesk-java-client
- Affected packages:
- hadoop-mapreduce-client-jobclient @ 2.7.3 (+9961 more)