pwneglyph logo
web javascript liquidjs template-injection prototype oracle exfiltration

Leak an inherited secret by observing how a LiquidJS sort filter orders attacker probe values around it.

Prototype-Inherited Secret Leak through LiquidJS sort_natural

The template engine promises ownPropertyOnly, but some filters still look up inherited properties while sorting or comparing values. Relative order then leaks the hidden inherited secret.

Why It Works

  • A sort filter compares an inherited property; the resulting order tells you where the secret sits relative to your probes.

Vulnerable Pattern

  • Server-side JS templating with LiquidJS, prototype-based secret storage, and sorting filters applied to attacker-controlled arrays/objects.

Exploit Flow

  1. Place controlled probe values around the unknown inherited value.
  2. Observe the sort order to learn whether the secret is before, after, or between your probes.
  3. Repeat as a binary/ternary search until the full secret is reconstructed.

Variations

  • Other filters that compare or stringify inherited properties, not just sort_natural.

Common Blockers

  • Engine patched to enforce own properties consistently, or templates not exposing enough control over the compared values.

PoC Sketch

{{ users | sort_natural: "apiKey" | map: "name" | join: "," }}
{# add probe values aaa, mmm, zzz around the inherited secret #}

Good Situations To Use It

  • LiquidJS renders attacker-influenced collections.
  • A secret is stored on a prototype.
  • A comparison/sort filter touches inherited properties.

Sources

  • plfanzen2026/web/thank_you_javascript