Hi Victor,
>OIS relies on the context ClassLoader, or a stack walk when
attempting to resolve class types. A string allow list is simpler,
but you might also consider permitting the OIS to be given a specific
ClassLoader for type resolution, since these are different functions
where a ClassLoader can perform the function of the allow list, but
perhaps shouldn't, but still be responsible for class type resolution.
Given that Marshalling is envisioned to support use-site pluggable
input/output formats, we're having to consider the common capabilities
of formats to ensure the possibility of adapting to/from each of them.
Having implemented several such bridges over the past couple of years
it seems tractable. Of course there are a multitude of different risks
to account for and design around.
An SPI inferred from the stream format? Perhaps with an allow list for
stream formats?
String identity could be an attack surface for stream format selection,
an encrypted digest might be a better identifier, although the risk is
low, it might distinguish between versions, where the versioning system
is controlled by others? A developer may want to constrain or limit
not only stream formats, but versions or implementations of the format.
It would be nice if there were hooks in there for checking for an
authenticated Subject with caller-constrained principals.
> We needed to support existing inheritance hierarchies of
Serializable objects, and we had code that is compiled separately and
comes together at runtime, so we couldn't rely on the compiler checks
for generic collections and built collection type validators to
address that.
Perhaps unsurprisingly, variants and especially dynamic type
restrictions tend to be challenging to encode in a non-cumbersome way.
We're considering generating record classes dynamically from schema,
when they don't exist locally, to support existing implementations, but
with transparent protocols, it's not necessary as as the data can be
introspected.
Cheers,
Peter.
On 2026-08-28 09:08, Peter Firmstone wrote:
Hi Victor,
Indeed, the ability to limit the types permitted to be loaded
(contextually to what is unmarshalled) is important to minimize
unmarshalling-associated risks. In my work on Marshalling I
currently rely on an allow-list (essentially String -> Class, as I
currently find ClassLoader to have a rather large API surface for
this purpose) since parsing a schema descriptor is resolving types.
Transparent protocols allow for more inspection than opaque
protocols, the latter limits the allow list to classes. Our current
wire protocol allows deep introspection, but I haven't given this
enough thought at this stage as to how an API might look for a
transparent protocol, vs opaque. OIS relies on the context
ClassLoader, or a stack walk when attempting to resolve class types.
A string allow list is simpler, but you might also consider
permitting the OIS to be given a specific ClassLoader for type
resolution, since these are different functions where a ClassLoader
can perform the function of the allow list, but perhaps shouldn't,
but still be responsible for class type resolution.
For schemaless payloads, the schema needs to be either known in
advance, or be determinable from the shape of the data itself.
I did consider this, and it really depends on the implementation, but
addressing transparency and deterministic behaviour is a
simplification that provides more certainty around security,
favouring the developer, or using inference which favours attackers
by providing options, similar to how a TLS protocol can be downgraded
to a less secure version. I didn't consider my capability sufficient
to implement the latter.
Current designs of Marshalling are essentially T -> record -> output
and input -> record -> T where the record serves both as schema
definition (using the record components as both names and types are
present at runtime). This encoding also permits versioning
(structure-as-version) as well as translation (record-to-enum-value,
record-to-cache-lookup, or equivalent).
This has the benefit of type safety, and since records don't support
inheritance hierarchies, it's an elegant solution. We needed to
support existing inheritance hierarchies of Serializable objects, and
we had code that is compiled separately and comes together at
runtime, so we couldn't rely on the compiler checks for generic
collections and built collection type validators to address that.
I've been trialling AI since April this year. I've developed
standards I can't share on this list, since I've had AI agents assist
with their documentation, they're available for viewing on GitHub and
anything prior to April is AI free, and all AI contributions are
documented in git commits.
I've attached a text file that demonstrates the capabilities of the
serialisation protocol. I haven't invented a new protocol; it's DER
ASN.1, with canonical ordering rules for Collection interfaces that
allow for cross-language collection types.
JGDMS/JGDMS/examples/wire-protocol-showcase at trunk ·
pfirmstone/JGDMS
<https://github.com/pfirmstone/JGDMS/tree/trunk/JGDMS/examples/wire-protocol-showcase>
Note the adversarial test code that produced the attachment was
written with AI assistance, genuinely attacking it to find weaknesses
in the protocol.
>We don't think of the object's serial form as serialised fields;
they are serialised parameter arguments used to create new objects.
That resonates with how I view it as well.
:)
Cheers,
Peter.
--
Cheers,
√
Viktor Klang
Software Architect, Java Platform Group
Oracle