diff --git a/lib/command.ts b/lib/command.ts index 8fc166fb..ab0d5661 100644 --- a/lib/command.ts +++ b/lib/command.ts @@ -427,7 +427,20 @@ Command.setReplyTransformer("hgetall", function (result) { if (Array.isArray(result)) { const obj = {}; for (let i = 0; i < result.length; i += 2) { - obj[result[i]] = result[i + 1]; + const key = result[i]; + const value = result[i + 1]; + if (obj[key]) { + // can only be truthy if the property is special somehow, like '__proto__' or 'constructor' + // https://github.com/luin/ioredis/issues/1267 + Object.defineProperty(obj, key, { + value, + configurable: true, + enumerable: true, + writable: true, + }); + } else { + obj[key] = value; + } } return obj; } diff --git a/test/functional/hgetall.ts b/test/functional/hgetall.ts new file mode 100644 index 00000000..f4a38d8d --- /dev/null +++ b/test/functional/hgetall.ts @@ -0,0 +1,12 @@ +import Redis from "../../lib/redis"; +import { expect } from "chai"; + +describe("hgetall", function () { + it("should handle __proto__", async function () { + const redis = new Redis(); + await redis.hset("test_key", "__proto__", "hello"); + const ret = await redis.hgetall("test_key"); + expect(ret.__proto__).to.eql("hello"); + expect(Object.keys(ret)).to.eql(["__proto__"]); + }); +});