Skip to content

TINKERPOP-3279 Restrict GraphSON 1.0 embedded-type deserialization - #3586

Draft
GumpacG wants to merge 2 commits into
apache:3.7-devfrom
GumpacG:jackson-bug
Draft

TINKERPOP-3279 Restrict GraphSON 1.0 embedded-type deserialization#3586
GumpacG wants to merge 2 commits into
apache:3.7-devfrom
GumpacG:jackson-bug

Conversation

@GumpacG

@GumpacG GumpacG commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

GraphSON 1.0 with embedded types (TypeInfo.PARTIAL_TYPES) configured Jackson default typing with JsonTypeInfo.Id.CLASS and no PolymorphicTypeValidator. Reading a document reconstructed whatever class was named in its @class property, so a crafted document could name and construct (or merely load, running its static
initializer) any class on the classpath. It is reachable pre-auth via the typed GraphSON 1.0 wire serializer
GraphSONMessageSerializerV1 (application/vnd.gremlin-v1.0+json), and through io() reads and GraphSON 1.0
persistence. GraphSON 2.0/3.0 are unaffected: they resolve types through a fixed registry, not by arbitrary class name.

This change constrains that default typing while leaving legitimate value types working.

What changed

New API

  • GraphSONMapper.Builder.addAllowedTypeIdPrefix(String...) trusts additional class-name prefixes for GraphSON 1.0 embedded-type deserialization, in addition to the safe defaults. Intended for provider/application types read from trusted input.

Hardened (GraphSON 1.0 PARTIAL_TYPES only)

  • A custom PolymorphicTypeValidator decides a simple type id from its name, so a disallowed class is refused in validateSubClassName before it is loaded (its static initializer never runs). Array descriptors are unwrapped and allowed only when the component type is allowed; primitive arrays are allowed.
  • The allow-list is derived from the types GraphSON 2.0/3.0 register (reduced to package prefixes, since V1 names concrete implementations): java.lang, java.util, java.math, java.time, java.sql, org.apache.tinkerpop, minus the network packages java.net/java.nio.
  • A few safe value types in those excluded packages are allowed by exact name: java.net.InetAddress and java.net.URI (string-backed, no DNS, unlike java.net.URL).
  • java.lang.Class is exact-denied even though java.lang is allowed, so a java.lang.Class value cannot name and load an arbitrary class (Jackson would otherwise resolve it with initialize=true).
  • A GraphSON1dScreeningIdResolver refuses a parameterized type id (one containing <) before Jackson resolves it. This closes a bypass where a disallowed class hidden as a generic type argument was loaded before validation, and where enum type arguments were not validated at all (Jackson skips them). GraphSON 1.0 never emits a parameterized @class, so nothing legitimate is affected.

Behavior change

A GraphSON 1.0 typed document whose @class names a type outside the allowed set now fails on read:

org.apache.tinkerpop.shaded.jackson.databind.exc.InvalidTypeIdException:
Could not resolve type id ...: Configured `PolymorphicTypeValidator` ... denied resolution

Breaking changes and capability impact

Breaking: reading a GraphSON 1.0 typed document now fails, instead of deserializing, when its @class:

  • names a type outside the allow-list (a provider type registered through an IoRegistry, an application POJO, most java.net.*/java.nio.* types),
  • is java.lang.Class used as a value, or
  • is a parameterized/generic id.

A document written by an older version that embeds such a type may no longer be readable.

Restore a specific type for trusted input by trusting its package:

GraphSONMapper.build().version(GraphSONVersion.V1_0).typeInfo(TypeInfo.PARTIAL_TYPES)
        .addAllowedTypeIdPrefix("com.example.").create();

or migrate to GraphSON 3.0 / GraphBinary. Standard scalar, collection and array values, java.math/java.time/
java.sql values, java.net.InetAddress/java.net.URI, and TinkerPop graph types are unaffected. The restriction
gates reads; the write path still emits @class for any type, so a writer and reader should be configured consistently. (java.nio.ByteBuffer is written by V1 as a concrete subtype Jackson cannot reconstruct, so it was never round-trippable in V1 and remains refused on read.)

Testing

GraphSONMapperPartialEmbeddedTypeTest covers, on the default V1 mapper:

  • a disallowed @class is refused, and is not class-loaded (a static-init canary never fires);
  • arrays round-trip, and an array of a disallowed component type is refused;
  • a disallowed class named as a generic type argument is refused before it is loaded, and an enum type
    argument is refused (regression for the parameterized-id / enum bypass);
  • a java.lang.Class value is refused and not loaded;
  • a value in a denied network package (java.net.URL) is refused, while java.net.InetAddress and java.net.URI round-trip;
  • java.sql/java.util value types round-trip;
  • addAllowedTypeIdPrefix(...) re-enables an otherwise-denied package.

GraphSON 2.0/3.0 embedded-type and wire-serializer suites continue to pass unchanged.

Assisted-by: Kiro:claude-opus-4.8

Assisted-by: Kiro: Claude Opus 4.8
@GumpacG GumpacG changed the title Restrict GraphSON 1.0 embedded-type deserialization TINKERPOP-3279 Restrict GraphSON 1.0 embedded-type deserialization Jul 31, 2026
@codecov-commenter

codecov-commenter commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.55814% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.54%. Comparing base (4722890) to head (3563220).
⚠️ Report is 69 commits behind head on 3.7-dev.

Files with missing lines Patch % Lines
.../gremlin/structure/io/graphson/GraphSONMapper.java 82.55% 11 Missing and 4 partials ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             3.7-dev    #3586      +/-   ##
=============================================
+ Coverage      75.49%   75.54%   +0.04%     
- Complexity     13161    13209      +48     
=============================================
  Files           1092     1093       +1     
  Lines          67208    67355     +147     
  Branches        7391     7419      +28     
=============================================
+ Hits           50742    50884     +142     
- Misses         13837    13850      +13     
+ Partials        2629     2621       -8     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@GumpacG
GumpacG marked this pull request as draft August 5, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants