· 6 min read
An open Redis is the most reliably over-claimed finding in infrastructure testing. The write-up almost always ends with remote code execution, because for years you could set the working directory and the dump filename, write an RDB file into a cron directory or an SSH authorized_keys path, and get a shell. Redis 7 changed that. Most tooling did not.
We ran a full autonomous campaign against Redis 7.4.10 on 127.0.0.1:6379 with no password, protected mode off and a wildcard bind. The interesting result is not the compromise. It is which claim the agent dropped.
What the agent found
The messaging-cache specialist agent produced 9 findings. Five are marked exploited, meaning the effect was produced and captured, and four are confirmed from configuration evidence.
| Severity | Count |
|---|---|
| Critical | 3 (1 exploited, 2 confirmed) |
| High | 5 (4 exploited, 1 confirmed) |
| Medium | 1 (confirmed) |
| Low | 0 |
| Total | 9 |
The access itself took one command, and the ACL made the scope explicit:
bash -c 'timeout 15 redis-cli -h 127.0.0.1 -p 6379 PING'
bash -c 'timeout 15 redis-cli -h 127.0.0.1 -p 6379 CONFIG GET requirepass'
bash -c 'timeout 15 redis-cli -h 127.0.0.1 -p 6379 ACL LIST'
PING -> PONG
requirepass -> ""
ACL LIST -> "user default on nopass sanitize-payload ~* &* +@all"
protected-mode -> "no"
bind -> "* -::*"nopass ~* &* +@all is the whole risk in one line: no password, every key pattern, every channel, every command.
What it did with that access
- Read the seeded application data.
KEYS "*"returnedsession:admin, andGET session:adminreturned"role=admin;token=abcd1234". An unauthenticated client reading a live admin session token is a session hijack, without touching the application. - Wrote and cleaned up.
SET,GET, thenDELon a test key, so the write capability is proven and the instance is left as it was found. - Changed runtime configuration.
CONFIG SET loglevel debugandCONFIG SET maxmemory 0both returned OK, then the log level was reverted. - Executed server side Lua.
EVALran and returned the fullINFO serverblock, which is code execution inside the Redis sandbox. - Enumerated the dangerous command surface.
SLAVEOF,REPLICAOF,DEBUG,SHUTDOWNandFLUSHALLare all available, andCONFIG GET rename-commandreturned an empty array, so nothing had been renamed away.
The claim the agent gave up
Demoted: RDB-write remote code execution
The agent tried the classic path and recorded the failure verbatim:
CONFIG SET dir /tmp
-> (error) ERR CONFIG SET failed (possibly related to argument 'dir')
- can't set protected config
CONFIG SET dbfilename darkmoon_test.rdb
-> (error) ERR CONFIG SET failed (possibly related to argument 'dbfilename')
- can't set protected configRedis 7.x treats dir and dbfilename as protected configuration, so the file write primitive that the whole RDB technique depends on is gone. The executive summary of the report says it in one sentence: classic RDB-write RCE is mitigated by Redis 7.x protections, and MODULE LOAD is disabled. The Lua sandbox held too: os.execute was reported unavailable and io raised ERR Script attempted to access nonexistent global variable.
So the campaign closed with data-layer compromise and denial of service, not host compromise. That is a smaller headline and it is the accurate one. A report that claims RCE here would fail the first time a customer tried to reproduce it.
SLAVEOF and REPLICAOF are still recorded as high severity, because an attacker can point the instance at a rogue master and force it to load a replacement dataset, which is a data integrity and exfiltration vector even without file writes. The report is explicit that module loading is disabled at config level while replication remains usable.
Remediation
- Set
requirepassor, better, define real ACL users and remove the permissivedefaultuser. - Re-enable
protected-modeand bind to a specific interface instead of* -::*. - Rename or disable
SHUTDOWN,FLUSHALL,DEBUG,REPLICAOFandCONFIGfor application users. - Enable TLS.
CONFIG GET tls-portreturned0, so every command and every session token crossed the network in cleartext. - Treat any session token that lived in this instance as burned and rotate it.
A bug this run found in our own agent
The first Redis campaign we launched hung with zero findings. The cause was not the target. The model had been told by an internal tool check that redis-cli was unavailable, so it improvised a raw socket with bash /dev/tcp and cat. Redis never closes the connection, so cat blocked forever. We fixed it by adding an execution safety rule to all 14 expansion agents: never read a live socket that way, always use the dedicated client wrapped in bash -c, always with a timeout. Every command in this report has that shape, which is why they all start with bash -c 'timeout 15 ...'.
What this proves about autonomous pentesting
The value of an autonomous run is not that it finds the open port. Any scanner does that. It is that the agent attempts the escalation, records the exact refusal from the target, and then downgrades its own claim. A finding that says exploited has a raw response behind it. A finding that says mitigated has the error message behind it. Both are more useful than a severity label with nothing under it.
Darkmoon is GPL-3.0 and self hosted. Run it against a Redis you own and compare: source, docs.