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.
4 steps from start to impact.
Find a legacy Rails app that honors session IDs outside cookies
- Externally reachable Ruby on Rails application
- Rails version earlier than
1.2.6or incomplete fix state - URL-based sessions still accepted or cookie-only enforcement absent
- This is ancient software; most enterprises no longer run Rails
1.2.xin 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
28333 can flag this remotely, but precise confirmation still needs app-side version/config review.Pre-seed a session the attacker already knows
- Ability to generate or maintain a valid application session
- A delivery path to get the victim to use the attacker-controlled session
- 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
_session_id parameters in URLs, but many legacy apps log this poorly.Victim authenticates into the fixed session
- Victim interaction
- Victim must successfully authenticate
- Application must not rotate the session after login
- This is a per-user compromise path, not unauthenticated mass RCE
- Short session lifetimes, explicit logout, and login-time session regeneration reduce utility
Reuse the authenticated session
- Valid authenticated session remains active
- Attacker can replay the session before expiry or invalidation
- 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
The supporting signals.
| In-the-wild status | No 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 status | Not in CISA KEV as checked against the current cisagov/kev-data catalog; no KEV dateAdded exists for either CVE. |
| Proof-of-concept availability | Manual 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. |
| EPSS | CVE-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 vector | AV: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 versions | CVE-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 versions | Upstream 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 data | Poor 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 timeline | CVE-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 / source | Primary source is the Rails core team security/maintenance release chain; Tenable ties plugin 28333 directly to CVE-2007-5380 and CVE-2007-6077. |
noisgate verdict.
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.
Why this verdict
- Down from vendor medium: reachable population is tiny. Requiring Rails
1.2.xin 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.
What to do — in priority order.
- Force cookie-only sessions — Set
config.action_controller.session_options[:cookie_only] = trueor 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. - Rotate sessions on authentication — Ensure login issues a fresh session identifier with
reset_sessionor 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. - Block session identifiers in request URLs — At the reverse proxy or WAF, reject or alert on requests carrying
_session_idor 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. - 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.6is a strategic end state.
- 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.
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.
#!/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()
If you remember one thing.
Rails 1.2.6.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.