Getting attacker-controlled data into a user's trusted session, either because the server writes unvalidated input into it or because a client-side session cookie is unsigned or its signing key has...
Session Injection is the act of getting attacker-controlled data into a user's session state so it is later trusted by the application. It happens two ways: the server writes unvalidated user input into the session, or the attacker tampers with client-side session state (a cookie) that is not properly signed or whose signing/encryption key has leaked.
When a controller copies request input straight into the session, whatever the client sends becomes trusted server-side state for the rest of the session. This is the same root cause as mass assignment: the boundary between untrusted input and trusted state is missing.
# Rails controller
def update_profile
# Client controls params[:role]; it lands in the session verbatim
session[:role] = params[:role]
session[:user_id] = params[:user_id]
end
# Request
POST /profile
role=admin&user_id=1
# Every later request now reads session[:role] == "admin"
# and authorizes accordingly
The session was never the vulnerability; the code chose to trust a client-supplied value. Session data should be derived from authenticated facts (the logged-in user record), not echoed from the request.
Frameworks that store the session in the cookie (Rails CookieStore, signed JWTs, PHP with a known secret) rely entirely on a signature or encryption to keep the client from editing it. If signing is absent, or the signing key leaks or is guessable, the attacker can forge session contents at will.
# Rails signs and (in newer defaults) encrypts the cookie with secret_key_base.
# If secret_key_base is committed to git or is a weak/default value, an
# attacker can craft a valid cookie for an arbitrary session hash:
# { "user_id" => 1, "role" => "admin" }
# re-sign it with the leaked key, and the server accepts it as authentic.
# A cookie that is only base64-encoded (not signed) is trivially editable:
# eyJ1c2VyX2lkIjo0Miwicm9sZSI6InVzZXIifQ==
# => {"user_id":42,"role":"user"} flip "user" to "admin", re-encode
How the forged bytes are turned back into an object also matters: if the cookie is deserialized with an unsafe serializer, a leaked key escalates from session tampering to code execution. See Rails Session Serialization.
user_id in a client-side sessionsession[:user_id] = user.id after verifying credentials)secret_key_base as a secret: never commit it, rotate it if exposed