CVE-2023-38037
Description
ActiveSupport::EncryptedFile writes contents that will be encrypted to a temporary file. The temporary file's permissions are defaulted to the user's current umask settings, meaning that it's possible for other users on the same system to read the contents of the temporary file.
Attackers that have access to the file system could possibly read the contents of this temporary file while a user is editing it.
All users running an affected release should either upgrade or use one of the workarounds immediately.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
activesupportRubyGems | >= 5.2.0, < 6.1.7.5 | 6.1.7.5 |
activesupportRubyGems | >= 7.0.0, < 7.0.7.1 | 7.0.7.1 |
Patches
1a21d6edf35a6Use a temporary file for storing unencrypted files while editing
3 files changed · +26 −17
activesupport/lib/active_support/encrypted_file.rb+8 −9 modified@@ -1,7 +1,7 @@ # frozen_string_literal: true require "pathname" -require "tmpdir" +require "tempfile" require "active_support/message_encryptor" module ActiveSupport @@ -81,17 +81,16 @@ def change(&block) private def writing(contents) - tmp_file = "#{Process.pid}.#{content_path.basename.to_s.chomp('.enc')}" - tmp_path = Pathname.new File.join(Dir.tmpdir, tmp_file) - tmp_path.binwrite contents + Tempfile.create(["", "-" + content_path.basename.to_s.chomp(".enc")]) do |tmp_file| + tmp_path = Pathname.new(tmp_file) + tmp_path.binwrite contents - yield tmp_path + yield tmp_path - updated_contents = tmp_path.binread + updated_contents = tmp_path.binread - write(updated_contents) if updated_contents != contents - ensure - FileUtils.rm(tmp_path) if tmp_path&.exist? + write(updated_contents) if updated_contents != contents + end end
activesupport/test/encrypted_file_test.rb+8 −0 modified@@ -49,6 +49,14 @@ class EncryptedFileTest < ActiveSupport::TestCase assert_equal "#{@content} and went by the lake", @encrypted_file.read end + test "change sets restricted permissions" do + @encrypted_file.write(@content) + @encrypted_file.change do |file| + assert_predicate file, :owned? + assert_equal "100600", file.stat.mode.to_s(8), "Incorrect mode for #{file}" + end + end + test "raise MissingKeyError when key is missing" do assert_raise ActiveSupport::EncryptedFile::MissingKeyError do encrypted_file(@content_path, key_path: "", env_key: "").read
railties/lib/rails/secrets.rb+10 −8 modified@@ -1,6 +1,7 @@ # frozen_string_literal: true require "yaml" +require "tempfile" require "active_support/message_encryptor" module Rails @@ -87,17 +88,18 @@ def preprocess(path) end def writing(contents) - tmp_file = "#{File.basename(path)}.#{Process.pid}" - tmp_path = File.join(Dir.tmpdir, tmp_file) - IO.binwrite(tmp_path, contents) + file_name = "#{File.basename(path)}.#{Process.pid}" - yield tmp_path + Tempfile.create(["", "-" + file_name]) do |tmp_file| + tmp_path = Pathname.new(tmp_file) + tmp_path.binwrite contents - updated_contents = IO.binread(tmp_path) + yield tmp_path - write(updated_contents) if updated_contents != contents - ensure - FileUtils.rm(tmp_path) if File.exist?(tmp_path) + updated_contents = tmp_path.binread + + write(updated_contents) if updated_contents != contents + end end def encryptor
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-cr5q-6q9f-rq6qghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-38037ghsaADVISORY
- discuss.rubyonrails.org/t/cve-2023-38037-possible-file-disclosure-of-locally-encrypted-files/83544nvdWEB
- github.com/rails/rails/commit/a21d6edf35a60383dfa6c4da49e4b1aef5f00731ghsaWEB
- github.com/rails/rails/releases/tag/v7.0.7.1ghsaWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/activesupport/CVE-2023-38037.ymlghsaWEB
- security.netapp.com/advisory/ntap-20250214-0010ghsaWEB
- security.netapp.com/advisory/ntap-20250214-0010/nvd
News mentions
0No linked articles in our index yet.