From 421f4d85778ec20f98bd7ba7b735c78683fd0b65 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 22 Sep 2026 01:39:29 +0200 Subject: [PATCH 1/2] =?UTF-8?q?redis:=20a=20consumer's=20ACL=20loses=20the?= =?UTF-8?q?=20dangerous=20category=20=E2=80=94=20a=20key=20pattern=20does?= =?UTF-8?q?=20not=20confine=20FLUSHALL=20(novox/hq=20issue=20080)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/redis/client.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/redis/client.ts b/modules/redis/client.ts index d4eb35d..7ca6744 100644 --- a/modules/redis/client.ts +++ b/modules/redis/client.ts @@ -98,9 +98,14 @@ export class RedisClient { * clears any prior rules so the call is idempotent, then the user is enabled with the given * password, confined to keys matching `:*`, and allowed the ordinary command set. The * consumer connects as this user and can touch nothing outside its prefix. + * + * Minus the dangerous category: a key pattern confines commands that name keys, and FLUSHALL, + * FLUSHDB, CONFIG, SHUTDOWN and the rest of `@dangerous` name none — with `+@all` alone a + * consumer scoped to its own keys could still wipe the server (novox/hq issue 080). KEYS goes + * with them; SCAN stays, and is what a consumer should use anyway. */ async createAclUser(username: string, password: string, keyspacePrefix: string): Promise { - await this.command("ACL", "SETUSER", username, "reset", "on", `>${password}`, `~${keyspacePrefix}:*`, "+@all"); + await this.command("ACL", "SETUSER", username, "reset", "on", `>${password}`, `~${keyspacePrefix}:*`, "+@all", "-@dangerous"); } async deleteAclUser(username: string): Promise { From c71bbd497f188cd9ae00c8581db4e0b6d33559e6 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 22 Sep 2026 02:03:23 +0200 Subject: [PATCH 2/2] =?UTF-8?q?redis:=20INFO=20is=20allowed=20back=20?= =?UTF-8?q?=E2=80=94=20client=20libraries=20ask=20it=20at=20connect,=20and?= =?UTF-8?q?=20it=20reads=20nothing=20a=20consumer=20keeps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/redis/client.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/redis/client.ts b/modules/redis/client.ts index 7ca6744..93a355d 100644 --- a/modules/redis/client.ts +++ b/modules/redis/client.ts @@ -102,10 +102,11 @@ export class RedisClient { * Minus the dangerous category: a key pattern confines commands that name keys, and FLUSHALL, * FLUSHDB, CONFIG, SHUTDOWN and the rest of `@dangerous` name none — with `+@all` alone a * consumer scoped to its own keys could still wipe the server (novox/hq issue 080). KEYS goes - * with them; SCAN stays, and is what a consumer should use anyway. + * with them; SCAN stays, and is what a consumer should use anyway. INFO comes back: it is in the + * category, reads nothing a consumer keeps, and several client libraries ask it at connect. */ async createAclUser(username: string, password: string, keyspacePrefix: string): Promise { - await this.command("ACL", "SETUSER", username, "reset", "on", `>${password}`, `~${keyspacePrefix}:*`, "+@all", "-@dangerous"); + await this.command("ACL", "SETUSER", username, "reset", "on", `>${password}`, `~${keyspacePrefix}:*`, "+@all", "-@dangerous", "+info"); } async deleteAclUser(username: string): Promise {