How to securely delete (zeroize) a Ruby String
Sensitive data such as passwords, API tokens or private keys often live as simple String objects in memory. In Ruby however, simply dropping a reference doesn’t guarantee the underlying data is erased – memory may linger until garbage‑collected, or the object remains in memory until the process ends. In this post I’ll show how to securely delete a Ruby string by zeroizing (overwriting its contents with zero‑bytes) before dropping it, so you leave fewer traces of sensitive material in memory.
Fiddle
Fiddle is Ruby’s standard library for dynamically loading and interfacing with C libraries. It allows you to call C functions, access C data structures, and work with native libraries directly from Ruby. Since Ruby String objects are essentially byte arrays, Fiddle can work with their raw memory, making it possible to manipulate or pass string data to C functions efficiently.
We’ll use Fiddle here to peek at the actual memory of a string so you can see zeroization in action.
# frozen_string_literal: true
require "fiddle"
secret = "secret_data".dup # [1]
original_bytesize = secret.bytesize
pointer = Fiddle::Pointer[secret]
hex = pointer[0, original_bytesize].unpack1('H*')
p hex
# => "7365637265745f64617461"[1] Since # frozen_string_literal: true is enabled, we duplicate the string to ensure it is mutable. Frozen literals cannot be zeroized because Ruby will raise a FrozenError. This won’t be the case for a real application, since you will either generate byte secrets directly in your application or read some sensitive data from database or network.
Zeroization of a String
Let’s write a method for String that will fill the underlying memory with zeroes.
class String
def zeroize!
bytesize.times do |i|
setbyte(i, 0)
end
clear
end
endThe method iterates over each byte of the string and sets it to 0, then clears the string content with clear.
Verifying with Fiddle
Extending the initial example, let’s do the following:
# ...
p pointer[0, original_bytesize].unpack1('H*')
# before: "7365637265745f64617461"
secret.zeroize!
p pointer[0, original_bytesize].unpack1('H*')
# after: "0000000000000000000000"
p secret
# ""We can see that the value of the secret has changed to an empty string – that’s because we have also used the clear method – and the underlying memory is all zeroes.
Limitations
While zeroizing strings in Ruby is possible, the language has limitations when it comes to other types. Values like Integer, Float, or Time are immutable and stored in a way that makes safe in-memory erasure impossible at the Ruby level. True secure zeroization for these types would require handling memory directly in C. For applications with high-security requirements, Ruby may not be the best choice for managing sensitive data in memory.