Skip to content

Commit 34d6238

Browse files
redonkulusclaude
andcommitted
fix: reject spoofed URL objects with non-string toString() result
Validates that URL.toString() returns a primitive string before passing to serialize(), preventing code injection via Object.create(URL.prototype) spoofing. Adds a regression test covering the attack vector from PSECBUGS-108653. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 451af65 commit 34d6238

2 files changed

Lines changed: 17 additions & 1 deletion

File tree

index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,11 @@ module.exports = function serialize(obj, options) {
287287
}
288288

289289
if (type === 'L') {
290-
return "new URL(" + serialize(urls[valueIndex].toString(), options) + ")";
290+
var urlStr = urls[valueIndex].toString();
291+
if (typeof urlStr !== 'string') {
292+
throw new TypeError('URL.toString() must return a string');
293+
}
294+
return "new URL(" + serialize(urlStr, options) + ")";
291295
}
292296

293297
var fn = functions[valueIndex];

test/unit/serialize.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,18 @@ describe('serialize( obj )', function () {
535535
strictEqual(d instanceof URL, true);
536536
strictEqual(d.toString(), 'https://x.com/');
537537
});
538+
539+
it('should throw when serializing a spoofed URL with non-string toString()', function () {
540+
var fakeUrl = Object.create(URL.prototype);
541+
fakeUrl.toString = function () {
542+
return {
543+
toString: function () {
544+
return 'https://example.com/';
545+
}
546+
};
547+
};
548+
throws(function () { serialize({ url: fakeUrl }); }, TypeError);
549+
});
538550
});
539551

540552
describe('XSS', function () {

0 commit comments

Comments
 (0)