← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:28333 · CWE-384 · Disclosed 2007-11-24

Ruby on Rails Multiple Method Session Fixation

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a spare key hidden under the mat of a house built in 2007

Tenable plugin 28333 tracks a Rails session fixation issue chain around CVE-2007-5380 and its incomplete fix CVE-2007-6077. The practical exposure is Ruby on Rails before 1.2.6, especially deployments that still accept URL-based sessions instead of forcing cookie-only session handling; Tenable explicitly recommends upgrading to 1.2.6+ and setting config.action_controller.session_options[:cookie_only] = true.

The vendor's MEDIUM label is technically fair in a vacuum, but operationally this deserves a downgrade to LOW for enterprise patch triage. The decisive friction is not exploit complexity but reachable population: this only lands on extremely old Rails 1.2-era apps, and even there the attacker still needs a victim to authenticate into an attacker-known session. If you truly have this, the bigger problem is that you still have a 2007-era internet app in production.

"Real bug, but it only matters on museum-piece Rails apps with URL sessions still enabled."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find a legacy Rails app that honors session IDs outside cookies

The attacker first needs a Rails application old enough to still support URL-based session handling or otherwise fail to enforce cookie-only sessions. Tenable's detection is aimed at servers that appear to run vulnerable Rails versions and accept this older session model.
Conditions required:
  • Externally reachable Ruby on Rails application
  • Rails version earlier than 1.2.6 or incomplete fix state
  • URL-based sessions still accepted or cookie-only enforcement absent
Where this breaks in practice:
  • This is ancient software; most enterprises no longer run Rails 1.2.x in supported production stacks
  • Modern Rails defaults and common reverse-proxy patterns do not rely on URL session IDs
  • Internet-wide fingerprinting for this exact condition is weak, so attacker target selection is noisy
Detection/coverage: Nessus plugin 28333 can flag this remotely, but precise confirmation still needs app-side version/config review.
STEP 02

Pre-seed a session the attacker already knows

Session fixation is not about guessing a session ID; it is about getting the victim to use one the attacker already controls. In Rails' documented attack flow, the attacker first establishes a valid session, keeps it alive, and then coerces the victim into authenticating with that same session identifier.
Conditions required:
  • Ability to generate or maintain a valid application session
  • A delivery path to get the victim to use the attacker-controlled session
Where this breaks in practice:
  • Without XSS, header injection, or URL session acceptance, forcing the session ID onto a victim is materially harder
  • If login correctly rotates the session ID with reset_session, the chain dies here
Detection/coverage: WAFs and app logs may show suspicious _session_id parameters in URLs, but many legacy apps log this poorly.
STEP 03

Victim authenticates into the fixed session

Once the victim browses with the attacker-known session, they log in normally. The application then binds authenticated state to that existing session instead of issuing a fresh one, letting the attacker reuse it and impersonate the victim.
Conditions required:
  • Victim interaction
  • Victim must successfully authenticate
  • Application must not rotate the session after login
Where this breaks in practice:
  • This is a per-user compromise path, not unauthenticated mass RCE
  • Short session lifetimes, explicit logout, and login-time session regeneration reduce utility
Detection/coverage: Look for the same session ID reused across divergent IPs/user agents around a login event; many SIEM pipelines can detect this if session IDs are logged.
STEP 04

Reuse the authenticated session

The attacker reuses the already-authenticated session cookie or identifier to access the victim's account. Impact is usually account hijack within the application's permission model, not host compromise.
Conditions required:
  • Valid authenticated session remains active
  • Attacker can replay the session before expiry or invalidation
Where this breaks in practice:
  • Blast radius is bounded by one application session and victim privileges
  • MFA at login does not help after the session is established, but it does make repeated account takeover attempts less reusable if sessions are rotated
Detection/coverage: Application telemetry is better than network IDS here; EDR will usually see nothing because there is no code execution on the server.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo current active exploitation signal found. I found no listing for CVE-2007-5380 or CVE-2007-6077 in CISA KEV, and Tenable marks exploit availability as false.
KEV statusNot in CISA KEV as checked against the current cisagov/kev-data catalog; no KEV dateAdded exists for either CVE.
Proof-of-concept availabilityManual technique exists; no meaningful modern weaponized PoC located. Rails' own security guide documents the session fixation workflow, but I did not find a currently maintained exploit repo worth treating as commodity tooling.
EPSSCVE-2007-5380 is currently shown by a FIRST-derived feed at about 7.4% EPSS / 90.9th percentile. That sounds elevated until you remember EPSS does not account for the near-zero modern population of Rails 1.2.x.
CVSS vectorAV:N/AC:M/Au:N/C:P/I:P/A:P (6.8 / MEDIUM, CVSS v2). Translation: remotely reachable, no auth required, but the real attack still depends on session-seeding and victim login rather than direct server takeover.
Affected versionsCVE-2007-5380: Rails before 1.2.4. CVE-2007-6077: the 1.2.4 fix was incomplete, leaving Rails before 1.2.6 effectively exposed for this plugin's purposes.
Fixed versionsUpstream fix is Rails 1.2.6. Tenable also requires config.action_controller.session_options[:cookie_only] = true; distro advisories from Ubuntu/SUSE/Gentoo tracked this in late 2007.
Scanning/exposure dataPoor internet-wide fingerprintability. Shodan/Censys-style search is not a reliable measure for 'supports URL-based sessions', so exposure telemetry is weaker than for banner-identifiable CVEs. Practically, if you see this in your estate, it likely came from direct scanner interaction, not passive internet census.
Disclosure timelineCVE-2007-5380 was published 2007-10-19 after the initial Rails 1.2.4 maintenance release on 2007-10-05. The incomplete-fix follow-up CVE-2007-6077 was published 2007-11-21, and Rails shipped 1.2.6 on 2007-11-24.
Reporter / sourcePrimary source is the Rails core team security/maintenance release chain; Tenable ties plugin 28333 directly to CVE-2007-5380 and CVE-2007-6077.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to LOW (3.2/10)

The single biggest downward pressure is population and age: this hits only very old Rails applications, and even then only when session handling remains in a legacy, exploitable mode. This is an account-hijack-by-workflow problem on a narrow slice of obsolete deployments, not a broad modern enterprise compromise primitive.

HIGH Affected-version and fix-path mapping to Rails `1.2.6`
HIGH Attack-path friction from victim interaction and login-time session reuse
MEDIUM Current population/exposure estimate for still-reachable vulnerable apps

Why this verdict

  • Down from vendor medium: reachable population is tiny. Requiring Rails 1.2.x in 2026 means you're dealing with a legacy outlier, not a broad enterprise patch wave.
  • Down again: this is session fixation, not server-side code execution. The attacker gets user-session hijack inside the app's privilege model, not immediate host takeover.
  • Down again: the chain needs victim participation. The user still has to authenticate into an attacker-known session, and modern login flows that regenerate sessions break the exploit.
  • Residual risk remains because the pre-auth attacker position is real. If an exposed legacy app still honors URL-based sessions, the attack can be mounted remotely against targeted users.

Why not higher?

This is not mass-exploitable infrastructure takeover. The attack requires a very old application, a legacy session model, and successful victim login into an attacker-prepared session. Each of those prerequisites materially narrows real-world abuse compared with what the CVSS base vector suggests.

Why not lower?

I would not mark this IGNORE because a confirmed finding still represents a genuine account-compromise path on a live app. If a scanner positively identifies this on an internet-facing system, defenders should verify it rather than dismiss it as pure archaeology.

05 · Compensating Control

What to do — in priority order.

  1. Force cookie-only sessions — Set config.action_controller.session_options[:cookie_only] = true or the equivalent control in the app stack so session IDs are not accepted in URLs. For a LOW finding there is no SLA; treat this as backlog hygiene and apply in the next normal maintenance change if the app cannot be retired first.
  2. Rotate sessions on authentication — Ensure login issues a fresh session identifier with reset_session or equivalent session regeneration. This directly kills the fixation step by invalidating the attacker-known session after the user authenticates; again, no SLA here beyond normal backlog handling.
  3. Block session identifiers in request URLs — At the reverse proxy or WAF, reject or alert on requests carrying _session_id or similar session tokens in query strings. This is a practical safety net for legacy apps where code changes move slowly; for LOW, deploy during routine hardening work.
  4. Inventory and retire Rails 1.2-era apps — If this finding is real, the business problem is broader than one CVE. Treat the app as unsupported legacy technology and plan replacement or isolation during normal backlog governance rather than pretending 1.2.6 is a strategic end state.
What doesn't work
  • TLS alone doesn't solve this; encryption protects the transport, not the app's willingness to accept an attacker-controlled session identifier.
  • MFA at login doesn't prevent post-login session reuse if the application keeps the same session after authentication.
  • Password resets alone may not evict an already-established application session unless the app invalidates active sessions on credential change.
06 · Verification

Crowdsourced verification payload.

Run this on the application host or against a checked-out Rails app directory from CI. Invoke it as python3 verify_rails_session_fixation.py /path/to/app; no root privileges are needed, but the script needs read access to Gemfile.lock, config/environment.rb, or vendored Rails metadata.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# verify_rails_session_fixation.py
# Detect likely exposure to Rails session fixation covered by Nessus plugin 28333.
# Exit codes: 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN, 3 USAGE/ERROR

import os
import re
import sys
from pathlib import Path

USAGE = "Usage: python3 verify_rails_session_fixation.py /path/to/rails_app"


def parse_version_tuple(v):
    parts = re.findall(r"\d+", v)
    if not parts:
        return None
    nums = [int(x) for x in parts[:3]]
    while len(nums) < 3:
        nums.append(0)
    return tuple(nums)


def find_rails_version(app):
    # 1) Gemfile.lock
    lock = app / "Gemfile.lock"
    if lock.exists():
        text = lock.read_text(errors="ignore")
        m = re.search(r"^\s{4}rails \(([^)]+)\)", text, re.M)
        if m:
            return m.group(1).strip(), "Gemfile.lock"

    # 2) vendor/rails/railties/lib/rails/version.rb or VERSION.yml
    candidates = [
        app / "vendor" / "rails" / "railties" / "lib" / "rails" / "version.rb",
        app / "vendor" / "rails" / "railties" / "lib" / "rails" / "version.rb",
        app / "vendor" / "rails" / "VERSION.yml",
        app / "vendor" / "rails" / "version.rb",
    ]
    for c in candidates:
        if c.exists():
            text = c.read_text(errors="ignore")
            m = re.search(r"VERSION\s*=\s*['\"]([^'\"]+)['\"]", text)
            if m:
                return m.group(1).strip(), str(c.relative_to(app))
            m = re.search(r"([0-9]+\.[0-9]+\.[0-9]+)", text)
            if m:
                return m.group(1).strip(), str(c.relative_to(app))

    # 3) config/environment.rb RAILS_GEM_VERSION
    envrb = app / "config" / "environment.rb"
    if envrb.exists():
        text = envrb.read_text(errors="ignore")
        m = re.search(r"RAILS_GEM_VERSION\s*=\s*['\"]([^'\"]+)['\"]", text)
        if m:
            return m.group(1).strip(), "config/environment.rb"

    return None, None


def detect_cookie_only(app):
    paths = [
        app / "config" / "environment.rb",
        app / "config" / "initializers" / "session_store.rb",
    ]
    patterns_true = [
        r"session_options\s*\[\s*:cookie_only\s*\]\s*=\s*true",
        r"session_options\s*\[\s*:cookie_session_id_only\s*\]\s*=\s*true",
    ]
    patterns_false = [
        r"session_options\s*\[\s*:cookie_only\s*\]\s*=\s*false",
        r"session_options\s*\[\s*:cookie_session_id_only\s*\]\s*=\s*false",
    ]

    found_files = []
    for p in paths:
        if p.exists():
            text = p.read_text(errors="ignore")
            found_files.append(str(p.relative_to(app)))
            for pat in patterns_true:
                if re.search(pat, text):
                    return True, found_files
            for pat in patterns_false:
                if re.search(pat, text):
                    return False, found_files
    return None, found_files


def main():
    if len(sys.argv) != 2:
        print("UNKNOWN - " + USAGE)
        sys.exit(3)

    app = Path(sys.argv[1]).resolve()
    if not app.exists() or not app.is_dir():
        print(f"UNKNOWN - path not found or not a directory: {app}")
        sys.exit(3)

    version_str, source = find_rails_version(app)
    if not version_str:
        print("UNKNOWN - could not determine Rails version from Gemfile.lock, vendored Rails, or config/environment.rb")
        sys.exit(2)

    vt = parse_version_tuple(version_str)
    if not vt:
        print(f"UNKNOWN - unable to parse Rails version: {version_str}")
        sys.exit(2)

    cookie_only, checked = detect_cookie_only(app)

    # Logic aligned to plugin 28333 / Rails 1.2.6 guidance.
    if vt < (1, 2, 6):
        print(f"VULNERABLE - Rails {version_str} detected via {source}; versions earlier than 1.2.6 fall in scope for session fixation / incomplete fix")
        sys.exit(1)

    if vt >= (1, 2, 6) and cookie_only is True:
        checked_desc = ", ".join(checked) if checked else "config not inspected"
        print(f"PATCHED - Rails {version_str} via {source}; cookie-only session enforcement detected in {checked_desc}")
        sys.exit(0)

    if vt >= (1, 2, 6) and cookie_only is False:
        checked_desc = ", ".join(checked) if checked else "config not inspected"
        print(f"UNKNOWN - Rails {version_str} via {source}; explicit non-cookie-only session setting found in {checked_desc}. Review manually against legacy session handling.")
        sys.exit(2)

    checked_desc = ", ".join(checked) if checked else "no relevant config files found"
    print(f"UNKNOWN - Rails {version_str} via {source}; no explicit cookie-only setting found ({checked_desc}). Manual review required.")
    sys.exit(2)


if __name__ == "__main__":
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: first verify whether this is a real live Rails 1.2-era app or just a noisy legacy fingerprint in scan results. If real, force cookie-only sessions and login-time session rotation during normal engineering backlog work, but do not let this single CVE outrank modern remotely exploitable flaws; for a LOW verdict there is no noisgate mitigation SLA and no noisgate remediation SLA beyond backlog hygiene, so the right move is to fold this into a broader legacy-app retirement or containment plan rather than launch an emergency patch effort for Rails 1.2.6.

Sources

  1. Tenable Nessus Plugin 28333
  2. Rails 1.2.6 Security and Maintenance Release
  3. NVD CVE-2007-5380
  4. NVD CVE-2007-6077
  5. GitLab Advisory CVE-2007-5380
  6. GitLab Advisory CVE-2007-6077
  7. Rails Security Guide - Session Fixation
  8. CISA KEV Current Catalog JSON
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.