Security Glossary

Session Injection

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.

Trusting User Input Written Into the Session

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.

Tampering With Client-Side Session State

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.

Impact

  • Privilege escalation by setting a role, admin flag, or another user's ID
  • Authentication bypass by forging user_id in a client-side session
  • Remote code execution when a leaked key is combined with unsafe deserialization

Prevention

  • Never assign request parameters directly into the session; set only values derived from the authenticated user (e.g. session[:user_id] = user.id after verifying credentials)
  • Keep authorization attributes (role, permissions) out of the session and read them from the user record server-side
  • Sign and encrypt cookie-stored sessions, and treat secret_key_base as a secret: never commit it, rotate it if exposed
  • Use a safe session serializer (JSON, not Marshal) so a forged cookie cannot trigger deserialization code paths

See Also