Skip to main content

Unsafe Deserialization

Treat serialized objects as untrusted data and prevent input from selecting executable types, constructors, hooks, or object graphs.

Data that creates behavior

Deserialization reconstructs an in-memory value from bytes. Unsafe deserialization occurs when untrusted input can select classes, constructors, callbacks, proxies, templates, or object graphs with behavior that runs during or after reconstruction. A gadget is an existing code path that becomes dangerous when the attacker controls its objects and sequence.

The impact can include code execution, file access, network requests, privilege changes, denial of service, or bypass of an application invariant.

Prefer data-only formats

Use a data-only format with a strict schema. Map the parsed data into explicit application types. Reject unknown fields, unsupported variants, excessive nesting, duplicate keys where interpretation differs, and values outside documented bounds. Do not deserialize an arbitrary language-native object graph from an untrusted source.

Do not let input name a class or type to instantiate. If polymorphism is necessary, map a small external discriminator to a fixed internal constructor that has no side effects. Keep parsing separate from authorization and business execution.

Integrity and authority

A signature or message authentication code can prove that serialized bytes came from a holder of a key. It does not make unsafe object reconstruction safe, and it does not prove that every signer is authorized for every action. Rotate and scope signing keys, bind the message to purpose and version, and validate expiry and replay rules.

Run parsers with narrow filesystem, network, process, and secret access. Bound input size, nesting, collection count, references, decompression, and processing time. Keep dependencies current because gadget availability changes with the deployed class path.

Failure and residual risk

A denylist of known gadget classes is incomplete. A type allowlist can still include a dangerous callback. Data can pass schema validation and violate a cross-field or workflow invariant. A safe parser can feed an unsafe template or command later. A trusted queue or cache can carry attacker-controlled data from another compromised producer.

Pomerium boundary

Pomerium can authenticate access to an upstream endpoint. It cannot make the upstream serializer safe or constrain constructors available in its process. The application must choose a data-only format, apply a strict schema, separate parsing from action, and run with narrow authority.

Evaluation checklist

  • Does any untrusted or cross-service input reconstruct language-native objects?
  • Can the input select a class, constructor, callback, proxy, or executable hook?
  • Is there a strict schema with unknown-field, size, depth, and collection limits?
  • Are authenticity, authorization, freshness, and replay evaluated separately?
  • What filesystem, network, process, and secret authority does the parser hold?
  • Do tests cover gadget-like values, duplicate fields, deep graphs, decompression, and compromised producers?

Sources and further reading

Keep learning

Software and Application Security

Injection

Prevent attacker-controlled data from changing the structure or meaning of a command sent to an interpreter.

Learn this term

Get a Personalized Demo

Schedule a Call with a Pomerium Engineer

Get a Demo