SCRIPT LOAD

SCRIPT LOAD compiles and caches a Lua script without running it and returns its SHA1, seeding the cache for a later EVALSHA in a load-then-exec workflow.

2 ನಿಮಿಷದ ಓದುಅಕ್ಟೋ 2,2026 ರಂದು ನವೀಕರಿಸಲಾಗಿದೆflorianamette1 ಕೊಡುಗೆದಾರ
ನಿಮ್ಮ ಸಹಾಯಕವನ್ನು ಕೇಳಿ (MCP)GitHub ನಲ್ಲಿ ಸಂಪಾದಿಸಿ

SCRIPT LOAD <script> compiles a Lua script, stores it in the server's script cache, and returns its SHA1 digest, all without executing it. It is the staging half of the scripting workflow: the script sits ready in the cache, keyed by SHA1(script_body), waiting to be fired by EVALSHA.

The load-then-exec workflow#

Offensively, SCRIPT LOAD is valuable precisely because it separates staging from execution. An attacker who reaches a sink that permits SCRIPT LOAD can place a malicious, parameterized script into the cache and record the returned digest:

code
SCRIPT LOAD "return redis.call(unpack(ARGV))"
# -> "5f2e...c8"

The loaded body is a generic command dispatcher: unpack(ARGV) spreads however many arguments are supplied into redis.call, so it invokes whatever command name and arguments are passed at execution time with the correct arity (a fixed ARGV[1],ARGV[2],ARGV[3] form would pass a trailing nil and Redis rejects nil arguments). A single cached script then drives many script-allowed commands through EVALSHA:

code
EVALSHA 5f2e...c8 0 KEYS *
EVALSHA 5f2e...c8 0 GET sessions:admin
EVALSHA 5f2e...c8 0 SET sessions:admin forged-value

The dispatcher is still bound by the scripting sandbox: noscript commands such as CONFIG, SLAVEOF/REPLICAOF, and DEBUG are rejected inside the script, so an admin-config or write-to-disk path (see CONFIG SET abuse) must be driven by direct commands, not through this loaded dispatcher.

Because the digest is deterministic, the attacker can compute it offline from the intended body and begin issuing EVALSHA immediately after the load succeeds, without reading the load's response. This is useful over blind or one-directional channels such as an SSRF-smuggled RESP connection (see Command injection), where command output may not return but the staged script still executes.

Seeding for a split-sink chain#

The load and the execution need not share a connection or an injection point. Where one request can trigger SCRIPT LOAD and a different request can trigger EVALSHA, the cache is shared server-wide, so a script staged through the first is runnable through the second. This decouples the two halves of the attack and lets a short-lived write primitive seed a payload that a later, more limited primitive invokes.

Inspecting and persistence#

SCRIPT EXISTS <sha1> [sha1 ...] reports whether given digests are cached (returning 1 or 0 for each), useful to confirm a stage landed before firing it. The cache is in-memory and cleared by SCRIPT FLUSH or a server restart, so a staged digest may need re-loading after either. Loading the same body again is idempotent: it returns the same SHA1 and leaves the cache state unchanged, so re-seeding is cheap.

Tools#

  • redis-cli: stage a script with SCRIPT LOAD and confirm it with SCRIPT EXISTS.
  • Gopherus: smuggle the SCRIPT LOAD over an SSRF RESP connection.
  • Burp Repeater: deliver the load request through the sink.

References#