blitz-js / superjson

Safely serialize JavaScript expressions to a superset of JSON, which includes Dates, BigInts, and more.
MIT License
3.88k stars 83 forks source link

SuperJSON will serialize into objects that it can't deserialize #266

Closed tmcw closed 8 months ago

tmcw commented 9 months ago

Testcase, run in Deno, but the same will work in Node with the packages installed and without the npm: prefixes:

/** @jsxImportSource https://esm.sh/preact */
import SuperJSON from "npm:superjson";

const value = (
  <div>
    <h1>Hello, world!</h1>
  </div>
);

console.log(SuperJSON.serialize(value));
console.log(SuperJSON.deserialize(SuperJSON.serialize(value)));

SuperJSON has a validatePath method that makes sure it isn't reaching into constructors or other dangerous properties:

https://github.com/blitz-js/superjson/blob/main/src/accessDeep.ts#L14-L24

But it doesn't have the same on the generation side, so it can't round-trip objects with these properties. A distilled testcase now that I'm looking into it:

SuperJSON.deserialize(SuperJSON.serialize({ constructor: undefined }))

This is triggered because this serializes to

{
  json: { constructor: null },
  meta: { values: { constructor: [ "undefined" ] } }
}

I don't know exactly what a better behavior would be - possibly sanitizing these properties in serialized output, or skipping them instead of throwing in deserialization?