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 (class-validator@0.15.1):
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.
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 objectand the caller keeps using that same object. If a validated property is a
non-idempotent read (an accessor getter, a
Proxyget-trap, or a value derivedfrom mutable state), the value validated can differ from the value later used —
a validation TOCTOU that bypasses allowlist/authorization checks.
PoC (class-validator@0.15.1):
Reachability (honest). Not reachable from a plain JSON body (
JSON.parseyields 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) andzod(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.