# Risk map — redis/redis

> Canonical page: https://codevetter.com/unpack/redis/risk-map

# Risk map — redis/redis

Scanned commit c3215f019a4c11c35d438f241114e94730fe39e5 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The dominant risk class is memory-safety in hand-written C parsing code reachable pre-authentication: the RESP parser, the cluster bus packet decoder, and the RDB/DUMP loader all consume untrusted bytes. Authentication is layered and easy to misconfigure — protected-mode, ACL, an auto-generated cluster internal secret, and module-supplied auth callbacks. A second class is coupling risk: the propagation invariants in `call()`/`propagateNow()`, the ordering contract inside `beforeSleep()`, and the object-type registration checklist all fail silently or assert if a contributor misses a step. Finally, there is genuinely dead code — GCRA is compiled out and its test file is `if 0`'d — and a large `DEBUG` surface with 50+ subcommands guarded only by a config flag.
- The RESP parser is the pre-auth attack surface: `processMultibulkBuffer()` and `processInlineBuffer()` parse attacker-controlled bytes into `pendingCommand` structs before any AUTH check, and `readQueryFromClient()` performs manual pointer arithmetic (`(size_t)(c->bulklen+2)-(sdslen(c->querybuf)-c->qb_pos)`) to size big-argument reads. — [src/networking.c#L4008-4022](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/networking.c#L4008-L4022) [src/networking.c#L3215](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/networking.c#L3215) [src/networking.c#L3828-3862](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/networking.c#L3828-L3862)
- The cluster internal secret is auto-generated with `getRandomHexChars(server.cluster->internal_secret, CLUSTER_INTERNALSECRETLEN)` and converged across nodes by a lexicographic `memcmp(...) > 0` rule in the PING extension handler — meaning any node that can join the bus can influence the shared secret used to authenticate internal connections. — [src/cluster_legacy.c#L1048](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/cluster_legacy.c#L1048) [src/cluster_legacy.c#L2700-2760](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/cluster_legacy.c#L2700-L2760) [src/acl.c#L3341-3346](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/acl.c#L3341-L3346)
- Internal-secret password comparison correctly uses `time_independent_strcmp()`, but it is one of several parallel auth paths (`checkPasswordBasedAuth`, `ACLAuthenticateUser`, module auth callbacks) that must all stay consistent — a change to one does not automatically cover the others. — [src/acl.c#L3341-3350](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/acl.c#L3341-L3350) [src/acl.c#L1522-1560](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/acl.c#L1522-L1560) [tests/unit/moduleapi/moduleauth.tcl](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/tests/unit/moduleapi/moduleauth.tcl)
- `moduleLoad()` calls `dlopen(path, RTLD_NOW|RTLD_LOCAL)` on an operator-supplied path, giving any successfully loaded module full in-process code execution; the only guard is that `MODULE` carries `CMD_PROTECTED` and is gated by `server.enable_module_cmd`. — [src/module.c#L13698-13715](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/module.c#L13698-L13715) [src/server.c#L4732-4748](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L4732-L4748)
- `warnAboutInsecureConfig()` only logs — it never refuses to start. A server with `DefaultUser` NOPASS, `protected-mode no` and a `0.0.0.0`/`::` bind emits a WARNING and then serves traffic. — [src/server.c#L8593](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L8593) [src/server.c](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c)
- `redis-server --test-memory <mb>` and `--check-system` run arbitrary memory-stressing code (`memtest()`, `syscheck()`) directly from `main()` before any config or privilege handling, and `--test-memory` with a non-numeric argument silently becomes `atoi(...) == 0`. — [src/server.c#L8378-8392](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L8378-L8392)
- `src/debug.c` dispatches roughly 52 `DEBUG` subcommands via a chain of `strcasecmp(c->argv[1]->ptr, ...)` comparisons; the entire surface is protected only by the `enable-debug-command` config and `allowProtectedAction()`, and several subcommands (JMAP, SEGFAULT, SET-ACTIVE-EXPIRE, QUICKLIST-PACKED-THRESHOLD) can corrupt or crash a live server. — [src/debug.c](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/debug.c) [src/server.c#L4732-4748](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L4732-L4748)
- Adding a new object type is a documented multi-file checklist with no compiler enforcement — the `server.h` comment requires coordinated edits to `rdb.c` (save/load, possibly RDB_VERSION), `aof.c` (rewrite), `db.c` (`obj_type_name`, `copyCommand`), `debug.c` (`xorObjectDigest`, `serverLogObjectDebugInfo`) and `defrag.c` (`defragKey`). Missing one produces silent data or defrag corruption, not a build error. — [src/server.h#L928-940](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.h#L928-L940)
- GCRA is dead code in the shipped build: `src/gcra.c` is entirely inside `#ifdef ENABLE_GCRA`, `OBJ_GCRA`/`OBJ_TYPE_MAX 9` are conditional in `server.h`, the guard appears in `rdb.h`, `redismodule.h` and `acl.c`, and `tests/unit/gcra.tcl` disables its whole body with `if 0 {`. Building with `-DENABLE_GCRA` would activate untested code and change `OBJ_TYPE_MAX`, which is an RDB-visible constant. — [src/gcra.c#L9-22](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/gcra.c#L9-L22) [src/server.h#L917-928](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.h#L917-L928) [src/rdb.h#L88-94](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/rdb.h#L88-L94) [tests/unit/gcra.tcl#L1-5](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/tests/unit/gcra.tcl#L1-L5)
- `beforeSleep()` encodes at least four ordering invariants in comments rather than in code structure (TLS pending data before AOF flush; `clusterBeforeSleep()` before `blockedBeforeSleep()`; `blockedBeforeSleep()` before `flushAppendOnlyFile`; AOF flush before `handleClientsWithPendingWrites`). Reordering any of them breaks `appendfsync=always` durability guarantees without failing a test deterministically. — [src/server.c#L1990-2013](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L1990-L2013) [src/server.c#L2060-2072](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L2060-L2072)
- `propagateNow()` contains two assertions that convert logic errors into crashes rather than data loss: `debugServerAssert(duration != PROP_DURATION_UNKNOWN)` and the replica-pause assert. Both are reachable from any new command that queues propagation incorrectly. — [src/server.c#L3798-3818](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L3798-L3818)
- The query-buffer pooling scheme (`thread_reusable_qb` / `thread_reusable_qb_used` / `CLIENT_IO_REUSABLE_QUERYBUFFER`) is shared mutable state whose correctness depends on nested-execution detection; the code comment notes the private-buffer fallback exists only for `processEventsWhileBlocked()` re-entry. — [src/networking.c#L4032-4052](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/networking.c#L4032-L4052)
- `src/module.c` is 16,117 lines — the single largest blast-radius file. It owns command registration, `RM_Call`, command filters, keyspace hooks, data-type serialization and `dlopen`, so nearly every subsystem change can break the stable module ABI in `src/redismodule.h`. — [src/module.c](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/module.c) [src/redismodule.h](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/redismodule.h)
- Atomic slot migration carries its own trim-correctness risk: `ASM_DEBUG_TRIM_DEFAULT` auto-selects between background BIO-thread deletion and main-thread active deletion 'based on module subscriptions and client tracking', so keyspace notifications fire in one mode and not the other. — [src/cluster_asm.c#L54-60](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/cluster_asm.c#L54-L60) [src/cluster_asm.c#L3081-3150](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/cluster_asm.c#L3081-L3150)
- `make` recipes shell out to scripts that perform network operations without review gates: `scripts/modules-update.sh` and `modules/common.mk` clone from GitHub URLs in `modules.yaml`, and `common.mk` resolves ref kind by probing the remote with `git ls-remote` at recipe time — so a `branch:` pin silently follows a moving target. — [modules/modules.yaml#L15-30](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/modules/modules.yaml#L15-L30) [modules/common.mk#L5-20](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/modules/common.mk#L5-L20) [scripts/modules-update.sh](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/scripts/modules-update.sh)
- CI does not run the slow test tag on PRs (`./runtest --verbose --tags -slow`), and the heavy `daily.yml` matrix only triggers on PRs to release branches matching `'[0-9].[0-9]'` — so changes merged to `unstable` get comparatively thin pre-merge validation. — [.github/workflows/ci.yml#L18-21](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/.github/workflows/ci.yml#L18-L21) [.github/workflows/daily.yml#L1-10](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/.github/workflows/daily.yml#L1-L10)
- Sentinel mode initializes before config parsing and before the RDB/AOF check dispatch, and `sentinel.c` is 5,000+ lines sharing `server.c` globals with the normal server path — a startup-order change in `main()` can break sentinel in ways the default `./runtest` (which excludes sentinel) will not catch. (inferred) — [src/server.c#L8342-8352](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/server.c#L8342-L8352) [src/sentinel.c](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/src/sentinel.c) [runtest-sentinel](https://github.com/redis/redis/blob/c3215f019a4c11c35d438f241114e94730fe39e5/runtest-sentinel)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
