# Risk map — rails/rails

> Canonical page: https://codevetter.com/unpack/rails/risk-map

# Risk map — rails/rails

Scanned commit be63fd9b4449505b90038acb9d51c88c02694e7e (2026-09-21). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The dangerous paths are the ones that eval, shell out, decrypt secrets, or accept network input before an app's own auth. CSRF and host authorization changed meaning across load_defaults versions, so an edit that looks local can change every newly generated app. Several public framework routes (health, storage, mailbox ingress) are safe only when the app understands their actual guarantees. The release webhook and the local .Gemfile hook are smaller but real trust boundaries.
- RunnerCommand evals stdin or an arbitrary string in TOPLEVEL_BINDING after boot_application! and Rails.application.load_runner. That is an intentional RCE surface for anyone who can invoke bin/rails runner. — [railties/lib/rails/commands/runner/runner_command.rb#L30-L50](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/commands/runner/runner_command.rb#L30-L50)
- Credentials editing shells out with system(*Shellwords.split(ENV['VISUAL'] or ENV['EDITOR']), tempfile). Shellwords reduces word-splitting surprises, but the editor string is still an executable chosen by the environment, and a forking editor that does not wait will cause an immediate re-encrypt of an unedited file. — [railties/lib/rails/command/helpers/editor.rb#L11-L30](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/command/helpers/editor.rb#L11-L30) [railties/lib/rails/commands/credentials/credentials_command.rb#L116-L127](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/commands/credentials/credentials_command.rb#L116-L127)
- EncryptedFile follows ENV then key file, uses AES-128-GCM, and rejects keys whose length is not expected_key_length. Missing keys raise MissingKeyError naming both the key path and the env var. Invalid ciphertext surfaces as MessageEncryptor::InvalidMessage, which credentials diff and edit rescue and sometimes print the raw encrypted file. — [activesupport/lib/active_support/encrypted_file.rb#L30-L74](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activesupport/lib/active_support/encrypted_file.rb#L30-L74) [railties/lib/rails/commands/credentials/credentials_command.rb#L56-L58](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/commands/credentials/credentials_command.rb#L56-L58)
- If SECRET_KEY_BASE and credentials are both empty in a local environment, secret_key_base generates and stores a secret in tmp/local_secret.txt. SECRET_KEY_BASE_DUMMY forces that path so assets:precompile can run without production secrets. A dummy secret shipped into a real environment would make cookie and message forgeries trivial. — [railties/lib/rails/application.rb#L490-L508](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application.rb#L490-L508) [railties/lib/rails/application/configuration.rb#L557-L566](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application/configuration.rb#L557-L566)
- HostAuthorization exists to stop DNS rebinding. It returns 403 via a default response_app when the host is not permitted, and logs the blocked host at error. ALLOWED_HOSTS_IN_DEVELOPMENT is .localhost, .test, 0.0.0.0/0, and ::/0. config.host_authorization exclude can opt a path out. — [actionpack/lib/action_dispatch/middleware/host_authorization.rb#L5-L23](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_dispatch/middleware/host_authorization.rb#L5-L23) [actionpack/lib/action_dispatch/middleware/host_authorization.rb#L23](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_dispatch/middleware/host_authorization.rb#L23) [railties/lib/rails/application/default_middleware_stack.rb#L16-L18](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application/default_middleware_stack.rb#L16-L18)
- load_defaults 8.2 sets forgery_protection_verification_strategy to :header_only, default_protect_from_forgery_with to :exception, and removes X-XSS-Protection and X-Download-Options from the default security headers. Apps that stay on an older load_defaults keep the previous token-based behavior. protect_from_forgery without an explicit with: warns when the default is still :null_session. — [railties/lib/rails/application/configuration.rb#L369-L386](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application/configuration.rb#L369-L386) [actionpack/lib/action_controller/metal/request_forgery_protection.rb#L260-L309](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_controller/metal/request_forgery_protection.rb#L260-L309)
- sanitize_sql_for_conditions returns a String argument unchanged, so callers who pass an already-interpolated SQL fragment get no quoting. The safe form is the array or named-bind form. This is the classic injection footgun at the framework boundary. — [activerecord/lib/active_record/sanitization.rb#L20-L39](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activerecord/lib/active_record/sanitization.rb#L20-L39)
- Rails::HealthController#show returns 200 whenever rendering succeeds. The class comment states it does not check the database or Redis, and that pointing a load balancer at it can restart pods for the wrong reason if an app later adds those checks carelessly. — [railties/lib/rails/health_controller.rb#L28-L40](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/health_controller.rb#L28-L40)
- Action Mailbox mounts POSTs at /rails/action_mailbox/{postmark,relay,sendgrid,mandrill}/inbound_emails and /rails/action_mailbox/mailgun/inbound_emails/mime on the application routes, plus a conductor that can create and incinerate emails. Those ingress controllers are the authentication boundary for inbound mail; the route file itself does not show a shared secret check. — [actionmailbox/config/routes.rb#L3-L25](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionmailbox/config/routes.rb#L3-L25)
- Active Storage exposes signed_id blob and representation URLs and a disk service PUT /disk/:encoded_token plus direct upload creation. Confidentiality of stored files depends on signed-id expiry and the service, not on a session. — [activestorage/config/routes.rb#L3-L16](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activestorage/config/routes.rb#L3-L16) [activestorage/lib/active_storage/service.rb#L69-L73](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activestorage/lib/active_storage/service.rb#L69-L73)
- Rakefile task publish_docs POSTs to http://api.rubyonrails.org:8080/rails-master-hook with Net::HTTP and no credentials in the request. The comment says a GitHub webhook is what normally triggers doc publishing, and that humans should not run the task. — [Rakefile#L183-L199](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/Rakefile#L183-L199)
- The root Gemfile instance_evals ./.Gemfile when that file exists, so a local untracked file executes during every bundle install of the framework. — [Gemfile#L130-L132](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/Gemfile#L130-L132)
- load_defaults is a single case ladder from 5.0 through 8.2 where each version calls the previous one. Changing an assignment inside when 8.2, or inserting a version in the wrong place, changes defaults for every app that generated config.load_defaults at that version. The generator writes that call into config/application.rb. — [railties/lib/rails/application/configuration.rb#L96-L115](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application/configuration.rb#L96-L115) [railties/lib/rails/application/configuration.rb#L336-L406](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application/configuration.rb#L336-L406) [railties/lib/rails/generators/rails/app/templates/config/application.rb.tt#L11-L16](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/generators/rails/app/templates/config/application.rb.tt#L11-L16)
- load_defaults 8.0 sets Regexp.timeout ||= 1 when the Ruby supports it, which can raise on previously legal long matches. 8.1 turns YJIT off when Rails.env.local? and on otherwise. Both are process-wide, not per-request. — [railties/lib/rails/application/configuration.rb#L336-L350](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application/configuration.rb#L336-L350)
- Railtie initializers share one ordered list with the application. A before/after name that does not match, or a railtie loaded after initialize!, silently misses the boot. rails/all.rb's require order is the supported composition order, and Releaser::FRAMEWORKS comments that Action Mailbox must follow Active Record. — [railties/lib/rails/railtie.rb#L50-L72](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/railtie.rb#L50-L72) [railties/lib/rails/all.rb#L5-L16](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/all.rb#L5-L16) [tools/releaser/lib/releaser.rb#L8-L22](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/tools/releaser/lib/releaser.rb#L8-L22)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
