May 26, 2023·4 min read·engineeringperlsecurityserialization

Storable's stronger warning rejects a safe untrusted-data mode

A documentation change makes Storable's security contract explicit. Disabling individual reconstruction features does not make it safe to deserialize untrusted input.

A serialization library can offer switches that remove particular dangers without offering a configuration suitable for hostile input. Storable's documentation now makes that distinction explicit. Its security warning says that no configuration makes processing untrusted Storable data safe. The change concerns the contract that callers should rely on, not a newly added parser option.

Yves Orton's May 26 change announcement says the commit changes no code. It strengthens the warning because options that mitigate specific problems do not amount to a safety guarantee. The updated Storable source and documentation explain why reconstruction is more powerful than reading a collection of passive values.

I like Perl's ability to move directly between text and useful data structures. That convenience makes the distinction especially important here. A representation that preserves Perl objects can also preserve instructions about which behavior the receiving process should invoke.

Reconstruction can execute application behavior

Storable supports optional serialization of code references. Its documentation describes using B::Deparse when serialization is enabled and evaluating the result when deserialization is enabled. Code-reference deserialization is off by default. Turning it on clearly gives the incoming representation a route to executable Perl.

However, the revised warning does not stop at code references. Deserializing an object can load the module corresponding to its class. The warning says manipulated module names can cause almost arbitrary code to load. A caller that leaves explicit code-reference evaluation disabled has therefore not removed every behavior-triggering part of reconstruction.

Objects also have destruction behavior. The warning describes a crafted document placing an object in a hash entry that a later key/value pair replaces. The replacement can destroy the earlier object during deserialization and invoke its destructor immediately. Waiting until after thaw returns to inspect the result does not place that destructor invocation behind the inspection.

This is the central timing problem. If processing the serialized representation already invokes behavior, a later validation pass is too late to prevent that behavior. Checking the eventual shape of the returned data does not establish that the process remained unaffected while producing it.

Hooks are part of the format's power

The documented STORABLE_thaw mechanism gives a class a hook during deserialization. Storable creates an empty object and passes it to the hook, along with the serialized content and related arguments. The hook can populate the instance according to the class's own rules.

When Storable cannot find the hook, the documentation says it tries to load the class dynamically and searches again. That facility supports objects whose state needs class-specific reconstruction. It also explains why the class name in a representation has consequences beyond choosing a label for an ordinary hash.

The separate STORABLE_attach hook handles objects that represent process-level resources. Its documentation discusses caches and shared resources as motivations. Instead of populating a newly created independent object, this hook returns an object directly. Storable's reconstruction model deliberately accommodates application behavior that a simple value-only decoder would not need.

Those facilities are useful when the producer and consumer operate within an appropriate trust relationship. Their usefulness does not establish that arbitrary documents should be allowed to select them. The security clarification follows from the difference between preserving a rich runtime structure and accepting a constrained external message.

Individual flags remain individual mitigations

The security section describes flags for disabling blessing and tying during retrieval. It identifies BLESS_OK as 2 and TIE_OK as 4, with the default combined setting of 6. Removing a flag disables the corresponding capability. The new introductory warning says these options do not form a complete protection against untrusted data.

That wording prevents a misleading inference from an option's name. Removing blessing is evidence that blessing has been disabled under that setting. It is not evidence that the entire decoder is suitable for hostile bytes. The documented risks also include segmentation faults and privilege escalation, which cannot be reduced to the code-reference switch alone.

Likewise, trapping a reported decoding exception does not establish safe parsing. The module documents exception-based error handling, but a normal error-reporting interface makes no promise about the absence of the security failures in its warning. A caller needs the security contract as well as the function's error contract.

I regard the documentation change as a correction to how an application should choose its input boundary. A configuration recipe can address a named behavior. It cannot justify a broader guarantee that the library's maintainers explicitly reject.

Format choice follows the required data

The revised warning points callers with untrusted input toward less powerful serialization formats and implementations. It distinguishes sufficiently simple data from structures containing Perl-specific types. That distinction begins with what the receiver actually needs to reconstruct. A message carrying ordinary values does not need the authority to rebuild arbitrary application objects.

The recommendation also retains qualifications for more capable alternatives. The documentation specifically notes that Sereal is unsafe by default and requires configuration to mitigate its issues. Replacing a library name without reading its own decoding contract would miss the point of the clarification.

The May change leaves Storable's implementation intact while making its permitted trust assumptions harder to misread. Callers can continue to use its reconstruction facilities for trusted data. For untrusted documents, the documentation now states that combining its mitigation switches does not produce a supported safe mode.