Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2025-55193

CVE-2025-55193: Active Record Information Disclosure Flaw

CVE-2025-55193 is an information disclosure vulnerability in Active Record that allows unescaped ANSI sequences in logs. This article covers the technical details, affected versions, security impact, and mitigation strategies.

Published:

CVE-2025-55193 Overview

CVE-2025-55193 affects Active Record, the Object-Relational Mapping (ORM) component of Ruby on Rails. The vulnerability occurs when the ID passed to find or similar lookup methods is logged without escaping. When the resulting ActiveRecord::RecordNotFound error message is written directly to a terminal, attacker-controlled input may include unescaped ANSI escape sequences. This condition maps to [CWE-150] (Improper Neutralization of Escape, Meta, or Control Sequences). The issue is patched in Active Record versions 7.1.5.2, 7.2.2.2, and 8.0.2.1.

Critical Impact

An attacker can inject ANSI control sequences into terminal-rendered Rails log output, potentially manipulating displayed content, hiding activity, or spoofing operator-facing messages.

Affected Products

  • Active Record versions prior to 7.1.5.2 in the 7.1.x series
  • Active Record versions prior to 7.2.2.2 in the 7.2.x series
  • Active Record versions prior to 8.0.2.1 in the 8.0.x series

Discovery Timeline

  • 2025-08-13 - CVE-2025-55193 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2025-55193

Vulnerability Analysis

Active Record raises RecordNotFound when methods such as find cannot locate a record. The error message is constructed by interpolating the primary key value directly into a string, for example "Couldn't find User with 'id'=#{id}". Because Ruby's default string interpolation calls to_s rather than inspect, non-printable bytes, including ANSI escape sequences beginning with the ESC character (\\x1b), pass through unchanged. When this message is logged and the log stream is a terminal, the terminal interprets the escape sequences as formatting or cursor control commands.

This is a log injection issue, not a code execution flaw. An attacker who can submit a crafted ID value to a Rails controller can cause operator log output to contain arbitrary color changes, cursor moves, screen clears, or forged text lines that appear legitimate to an administrator reviewing logs in a shell session.

Root Cause

The root cause is unsafe string formatting of untrusted input in error construction paths within activerecord/lib/active_record/core.rb and activerecord/lib/active_record/relation/finder_methods.rb. The affected code interpolated id and ids values using implicit to_s conversion, which preserves control bytes. The fix routes those values through inspect, which produces a safely quoted and escaped Ruby literal representation.

Attack Vector

The attack vector is network-accessible: any endpoint that passes user-supplied identifiers into an Active Record find (for example, Model.find(params[:id])) can trigger the vulnerable error path. The attacker submits an ID containing ANSI escape sequences. When the resulting RecordNotFound is logged to a terminal-attached log destination, the escape sequences are rendered by the terminal.

ruby
# Security patch in activerecord/lib/active_record/core.rb
# Call inspect on ids in RecordNotFound error
         return super if StatementCache.unsupported_value?(id)

         cached_find_by([primary_key], [id]) ||
-          raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}", name, primary_key, id))
+          raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id.inspect}", name, primary_key, id))
       end

       def find_by(*args) # :nodoc:
# Source: https://github.com/rails/rails/commit/3beef20013736fd52c5dcfdf061f7999ba318290
ruby
# Security patch in activerecord/lib/active_record/relation/finder_methods.rb
# Call inspect on ids in RecordNotFound error
         error << " with#{conditions}" if conditions
         raise RecordNotFound.new(error, name, key)
       elsif Array.wrap(ids).size == 1
-        error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
+        id = Array.wrap(ids)[0]
+        error = "Couldn't find #{name} with '#{key}'=#{id.inspect}#{conditions}"
         raise RecordNotFound.new(error, name, key, ids)
       else
         error = +"Couldn't find all #{name.pluralize} with '#{key}': "
-        error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
-        error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if not_found_ids
+        error << "(#{ids.map(&:inspect).join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
+        error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.map(&:inspect).join(', ')}." if not_found_ids
         raise RecordNotFound.new(error, name, key, ids)
       end
     end
# Source: https://github.com/rails/rails/commit/3beef20013736fd52c5dcfdf061f7999ba318290

Routing values through inspect produces representations like "\e[31mattacker\e[0m", neutralizing terminal interpretation.

Detection Methods for CVE-2025-55193

Indicators of Compromise

  • Log lines containing raw ESC bytes (\\x1b / 0x1B) or CSI sequences (for example \\x1b[) inside RecordNotFound error messages.
  • Repeated ActiveRecord::RecordNotFound entries where the interpolated id value contains non-alphanumeric or non-printable characters.
  • Request logs with URL-encoded escape sequences (%1B, %1b) in path or query parameters targeting resource lookup endpoints.

Detection Strategies

  • Grep or query centralized logs for the byte pattern \\x1b\[ co-occurring with RecordNotFound or Couldn't find.
  • Add a log-ingest parser rule that flags any application log line containing control characters outside tab, carriage return, and line feed.
  • Review web access logs for suspicious id parameter values containing encoded ANSI or shell control characters, especially against controllers that call find.

Monitoring Recommendations

  • Ship Rails production logs to a structured backend (JSON or OCSF) where control bytes are escaped at write time rather than rendered.
  • Alert on unusual spikes in RecordNotFound exceptions that could indicate probing for injection payloads.
  • Verify installed gem versions across the fleet by inventorying Gemfile.lock entries for the activerecord gem.

How to Mitigate CVE-2025-55193

Immediate Actions Required

  • Upgrade Active Record to 7.1.5.2, 7.2.2.2, or 8.0.2.1 depending on the Rails branch in use.
  • Audit application controllers for direct use of Model.find(params[:id]) and similar lookups exposed to untrusted input.
  • Route production logs through a non-terminal sink (file, syslog, or SIEM collector) that does not interpret ANSI sequences.

Patch Information

The fix is delivered in Active Record 7.1.5.2, 7.2.2.2, and 8.0.2.1. The patch calls inspect on id and ids values before interpolating them into the RecordNotFound message, ensuring control characters are represented as escaped Ruby string literals. See the GitHub Security Advisory GHSA-76r7-hhxj-r776 and commits 3beef20, 568c0bc, and 6a944ca.

Workarounds

  • Coerce or validate identifiers before passing them to Active Record finders, for example by calling Integer(params[:id]) or applying a strict regex.
  • Wrap RecordNotFound handling in a custom rescue that sanitizes control characters from messages before logging.
  • Avoid attaching production log streams to interactive terminals; use file-based or structured logging with escape-byte stripping.
bash
# Update Active Record via Bundler
bundle update activerecord

# Or pin the patched version in Gemfile, then bundle install
# gem "rails", "~> 8.0.2.1"
# gem "rails", "~> 7.2.2.2"
# gem "rails", "~> 7.1.5.2"

# Verify installed version
bundle info activerecord | grep -i version

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.