Skip to content
Innovation & Growth

Rails' 8.2 defaults drop the Marshal fallback for signed messages

The change takes effect when an app sets load_defaults 8.2. Apps on 7.1 through 8.1 keep the old fallback.

W
WebPulse Newsroom
AI-assisted · 4 min read
Share on X LinkedIn
Rails' 8.2 defaults drop the Marshal fallback for signed messages
In brief
  • Ruby on Rails says apps that set config.load_defaults 8.2 no longer fall back to reading Marshal payloads in signed or encrypted messages. Apps on 7.1 through 8.1 keep the fallback.
  • The same weekly update tightens a local secret file's permissions and fixes a redirect that could send visitors to another host.
  • Ask your team which Rails version and defaults each app runs, and whether anything still sends Marshal messages.

A default is a decision someone else made for you

A framework's security depends less on its features than on its defaults. Most teams rarely reopen those choices. They inherit whatever was switched on when the app was created, and they tend to keep it.

Ruby on Rails' weekly update of October 23 shows this clearly. Rails reported 40 contributors to the codebase that week. Several of the changes tighten security behavior. In WebPulse's judgement, the most consequential one is the signed-message change. It takes effect only when an app sets config.load_defaults 8.2.

Rails' notes describe the change as one for new apps. Older apps on versions 7.1 through 8.1 keep the old behavior until a team chooses to move.

What changed for signed messages

Rails signs and encrypts small pieces of data that it hands out and later reads back. Two components do this work: MessageVerifier and MessageEncryptor. Rails says they cover signed IDs, signed GlobalIDs and Active Storage keys, among others.

Each message needs a format for the data inside it. JSON is plain data. Marshal is Ruby's built-in format, which can rebuild Ruby objects. Until now, apps could still read Marshal payloads even when JSON was the main format.

With config.load_defaults 8.2, Rails changes the message serializer default to :json. Messages from both components no longer fall back to deserializing Marshal. Apps on versions 7.1 through 8.1 stay on :json_allow_marshal, the mode that permits that fallback.

This is WebPulse's analysis, not Rails' stated reason. A format that rebuilds objects is a bigger target than one that only carries data. If an attacker gets a forged Marshal payload accepted, the app may build objects the attacker picked. Removing the fallback shrinks what an attacker could try to feed the app.

The change also carries a cost. Messages already issued in the old format may still be in circulation. Rails advises teams to confirm nothing still arrives as Marshal before switching. It points to the message_serializer_fallback.active_support notification for that check.

Two quieter fixes with real exposure

The first fix concerns the secret file for development and test, tmp/local_secret.txt. Until now, Rails created it with whatever default permissions the running process carried, often a umask of 022. Other accounts on the same machine could read it. Rails now writes it with owner-only 0600 permissions. On non-Windows platforms, an existing file is tightened when read. This matches how config/master.key is handled.

The file holds the secret_key_base for development and test. Anyone who can read it can learn a value the app relies on for trust.

The second fix concerns redirects. Rails gives an example: a redirect built from the template "/%{path}" received a request for /old/%2Finjected.example. The result began with two slashes. Browsers treat that as a link to another host, injected.example, not to the app's own site.

Rails now encodes the separator character when filling in the placeholder would add a scheme or host that the template never names. A template that deliberately names its own host, such as a CDN address, behaves as before.

For a business, the effect is plain. A link on your own domain could send customers to someone else's site.

Data integrity fixes in the same update

Rails also changed how rename_column works on SQLite. Before, Rails handled a rename by building a new table and replaying the SQL for indexes, check constraints and virtual columns exactly as written. If that SQL mentioned the old column name, the rename failed.

Rails lists further side effects of that approach. Triggers vanished, foreign keys in other tables stopped working, and a string primary key was lost.

Rails now uses SQLite's own ALTER TABLE ... RENAME COLUMN, which updates all of those. Teams that renamed SQLite columns in past migrations may want to check the results.

Defaults protect only the apps that adopt them

The lesson is that a secure default is a promise to projects that start with it. Existing projects collect it only by deciding to. The Marshal change is the clearest case, because Rails keeps the fallback for 7.1 through 8.1.

WebPulse's September 2026 scan of the Tranco top 10,000 domains found a platform on 2,491 of the 7,064 sites that responded. Rails was detected on 85 of those, or 3.4% of detected sites. That is a sample of large sites, not a count of all Rails apps.

Questions to put to your team

Ask which Rails version each production app runs, and which load_defaults value it sets. Ask whether anyone has watched the message_serializer_fallback.active_support notification, and what it shows.

Ask whether any routes build redirects from a string template with a path placeholder. Ask whether past SQLite column renames were checked for lost triggers or keys. Finally, ask who owns the decision to move older apps onto the newer defaults.

A safer default helps only after someone decides to adopt it.

Produced by the WebPulse Newsroom with AI assistance from the original reporting credited below, and checked against that source by our editorial review. How we use AI.
Original reporting: Ruby on Rails.

Share this insight