AUTH is not blocked while a BEGIN session transaction is open, and it unconditionally rewrites the connection's namespace prefix. Commands issued after the mid-transaction AUTH therefore land under a different namespace while sharing the same txm, so a single atomic commit mixes keys from two namespaces.
Evidence
AuthCommand::Execute rewrites the namespace with no open-transaction guard (src/redis_command.cpp:1503-1511):
if (ns_meta) {
ctx->authenticated = true;
ctx->ns = ns_meta->ns_name;
ctx->ns_meta = ns_meta;
ctx->ns_id = NamespacePrefix::MakePrefix(ns_meta->encoded_id, ns_meta->epoch...);
}
By contrast, WATCH is rejected during a session (src/redis_service.cpp:6016-6019: "ERR WATCH inside a BEGIN transaction"), and AUTH mid-MULTI is also rejected — but AUTH mid-BEGIN is not. In a BEGIN session, subsequent commands run immediately on ctx->txm, and key prefixing uses the now-changed ctx->ns_id.
Repro
BEGIN; SET a 1 (namespace N1) ; AUTH <token-for-N2>; SET b 2; COMMIT → a (N1) and b (N2) are committed atomically in one transaction, crossing the namespace isolation boundary.
Fix: reject AUTH (and any namespace switch) while ctx->txm != nullptr, as is already done for WATCH.
Found during a code audit (docs PR #492). Verified against source at the cited lines. Related: #493, #499.
🤖 Found with Claude Code
AUTHis not blocked while aBEGINsession transaction is open, and it unconditionally rewrites the connection's namespace prefix. Commands issued after the mid-transactionAUTHtherefore land under a different namespace while sharing the same txm, so a single atomic commit mixes keys from two namespaces.Evidence
AuthCommand::Executerewrites the namespace with no open-transaction guard (src/redis_command.cpp:1503-1511):By contrast,
WATCHis rejected during a session (src/redis_service.cpp:6016-6019:"ERR WATCH inside a BEGIN transaction"), andAUTHmid-MULTIis also rejected — butAUTHmid-BEGINis not. In aBEGINsession, subsequent commands run immediately onctx->txm, and key prefixing uses the now-changedctx->ns_id.Repro
BEGIN; SET a 1(namespace N1); AUTH <token-for-N2>; SET b 2; COMMIT→a(N1) andb(N2) are committed atomically in one transaction, crossing the namespace isolation boundary.Fix: reject
AUTH(and any namespace switch) whilectx->txm != nullptr, as is already done for WATCH.Found during a code audit (docs PR #492). Verified against source at the cited lines. Related: #493, #499.
🤖 Found with Claude Code