Security hardening: validateSync/validate inspect the live object → read-unstable properties (getters/Proxy) can bypass validation

Author: peaktwilightCreated Jul 14, 2026Updated Jul 14, 2026

Hi — a heads-up on a soundness issue with a security consequence. Private vulnerability reporting isn't enabled on the repo and there's no SECURITY.md contact, so I'm raising it here constructively (with the fix). Happy to move it private if you enable reporting.

Issue. validateSync(obj) / validate(obj) check the caller's live object and the caller keeps using that same object. If a validated property is a non-idempotent read (an accessor getter, a Proxy get-trap, or a value derived from mutable state), the value validated can differ from the value later used — a validation TOCTOU that bypasses allowlist/authorization checks.

PoC ([email protected]):

javascript
class Dto { @IsIn(["readonly","guest"]) role!: string; }
let n = 0;
const dto = Object.assign(new Dto(), { get role(){ return ++n === 1 ? "readonly" : "admin"; } });
validateSync(dto).length === 0;  // passes the allowlist
dto.role === "admin";            // app then uses the malicious value

Reachability (honest). Not reachable from a plain JSON body (JSON.parse yields inert data). It bites when validating class instances/models with getter accessors, Proxy-wrapped objects, or getters over mutable state — a real but conditional bypass. I'd rate it Medium.

Fix. Offer a materialized, read-stable snapshot of the validated data (read each property once into a fresh object), as joi (value) and zod (data) do; or at minimum document that validation reads the caller's live object and gives no read-stability guarantee.

Reported by 0sec (https://0sec.ai). No ask — just wanted you to have it + the fix.

Source: typestack/class-validator