Rails 6.0.3.2 restricts actionable errors to detailed exception mode
CVE-2020-8185 allowed untrusted requests to invoke pending application migrations. The patch changes the middleware condition that enables error actions.
A development error page can offer a useful repair button, but the action behind that button is still server-side functionality. Hiding the page is insufficient if its handler remains active under a broader production setting. Rails 6.0.3.2, released on June 17, corrects that boundary for actionable errors. The release contains a focused security patch for CVE-2020-8185.
The advisory describes untrusted users being able to run pending migrations in a production application. Its scope is limited to migration code already defined by the application and not yet run. The defect does not let a requester supply an arbitrary new migration body. That limit still leaves control over when an application's schema changes occur in the wrong hands.
I find Ruby's blocks convenient for attaching an operation to a named action. A framework must also define where that operation is available. An action intended to help a developer repair an error needs an activation condition matching that purpose, even when invoking the block itself is straightforward.
Actionable errors attach code to a name
The ActionableError implementation lets an error class register actions through a class macro. Each action has a name and a block. The source documentation illustrates a pending-migration error with an action that invokes the application's database migration task.
The dispatch operation obtains the actions associated with the error and looks up the requested name. If no matching action exists, it raises a non-actionable error. A valid action executes its registered block. The code therefore constrains execution to registered actions, but those actions can perform meaningful changes in the application.
This is a useful distinction in assessing the vulnerability. Restricting a request to preexisting code does not establish that the requester should be able to invoke that code. Migration execution is an application operation whose timing can matter independently of whether its definition is trusted.
The mechanism can be appropriate in a development workflow where the person viewing the error is also controlling the application environment. A production request has a different trust relationship. The middleware needs to enforce that boundary before dispatch reaches a registered block.
The old condition enabled too much
The release diff changes the predicate used by ActionDispatch::ActionableExceptions. Previously it checked request.show_exceptions? along with the request method and matching endpoint. The new code checks the internal action_dispatch.show_detailed_exceptions value instead.
Showing an exception response and allowing a detailed diagnostic interaction are different policies. The former can be part of an application's ordinary error handling. It does not imply that the remote requester should receive developer-oriented capabilities for repairing that error.
The advisory notes that disabling config.action_dispatch.show_exceptions avoids the vulnerable behavior, but that this is not the production default. That explains why the old condition was significant. A setting used for normal exception responses also governed access to a stronger action mechanism.
The revised predicate still requires the appropriate request method and endpoint. Changing the environment condition narrows when the handler participates. Requests that do not qualify pass to the next application component instead of dispatching an error action.
The regression test checks that actions remain inactive
The changed tests explicitly enable detailed exceptions for successful action cases. The test asserting that no action runs supplies the detailed-exceptions value as false. That verifies the security-relevant behavior at the middleware boundary.
A test that merely removed a repair button from rendered HTML would not establish the same property. The server can receive a request independently of whether a particular page generated it. The regression test concerns whether the registered action actually executes, which is the operation the boundary must control.
This also preserves the useful development feature. The positive cases continue exercising valid actions and failures when the detailed mode is enabled. The patch changes availability of the capability, without removing the action registration model or pretending every registered block is harmless.
The workaround removes the handler
For applications unable to apply the patch immediately, the advisory gives a middleware-removal workaround. The relevant configuration expression is:
config.middleware.delete ActionDispatch::ActionableExceptions
Removing the handler prevents this middleware from dispatching actionable-error requests. The recommendation concerns the component containing the vulnerable activation check. It does not require changing every application migration or renaming error classes.
I prefer this explanation to describing the issue as generic remote code execution. The actual capability is invoking pending application-defined migrations, and the actual fix is the middleware's activation policy. Those details explain both the impact and why a one-line predicate change is sufficient for this particular boundary.
The advisory credits Rafael França and Benoit Côté-Jodoin with independent discovery and Rafael with the patch. Rails 6.0.3.2 publishes that correction through the normal release channel. The code behind actionable errors remains available for its intended detailed-exception context, while production exception rendering no longer supplies the enabling condition by itself.