Brakeman

Ruby on Rails Static Analysis Security Tool

Brakeman 7.0.0 Released

Happy new year!

This release of Brakeman contains several breaking changes and updates to default behavior.

Changes since 6.2.2:

  • Default to using Prism parser if available (disable with --no-prism)
  • Disable following symbolic links by default (re-enable with --follow-symlinks)
  • Remove updated entry in Brakeman ignore files (Toby Hsieh)
  • Major changes to how rescanning works
  • Fix hardcoded globally excluded paths (#1830)
  • Always warn about deserializing from Marshal
  • Update eval check to be a little noisier
  • Output originalBaseUriIds for SARIF format report (#1889)
  • Add step (and timing) for finding files
  • Fix recursion when handling multiple assignment expressions (#1877)
  • Fix array/hash unknown index handling
  • Update terminal-table version
  • Add CSV library as explicit dependency for Ruby 3.4 support
  • Raise minimum Ruby version to 3.1

Default to Prism Parser

Prism is a new parser that has quickly been adopted across many Ruby implementations and code tools. In Ruby 3.4, it is now the default parser for Ruby itself.

Thankfully, Prism has also implemented translation layers for RubyParser and other existing parsers. This has allowed Brakeman (and other tools) to adopt Prism fairly easily. Even with the translation layer, Prism is typically a little faster than RubyParser. Line numbers may also shift slightly.

Brakeman now defaults to using Prism for parsing. The --prism and --no-prism options.

There are still some small incompatibilities - please report any instances where Brakeman outputs [Format Error].

(changes)

For better performance, Brakeman will no longer default to following symbolical links for directories. This behavior was added in Brakeman 6.2.1.

To re-enable the previous behavior, use the --follow-symlinks option.

(changes)

Drop Timestamp from Ignore Files

Brakeman will no longer add an updated entry when generating or updating an ignore file.

The entry was redundant with source control and could cause unnecessary merge conflicts.

(changes)

Updates to Rescanning

“Rescanning” in Brakeman (attempting to only scan changed files) has been broken and out of date for a long time. This release drops a lot of that old code.

To improve accuracy, rescanning will now only skip the file reading/parsing step for unchanged files. The rest of the scan will continue like a regular full scan. For many code bases, the read/parse step is the slowest part of the scan. However, it is very likely the current rescanning will be slower (but more accurate) than the old version.

Hopefully there will be additional improvements in this functionality over time.

For any tools wanting to use rescanning, the initial scan must set support_rescanning: true to enable caching of the parsed files. After that, the API is the same.

(changes)

Globally Excluded Paths

Brakeman has a set of paths that it never scans:

  generators/
  lib/tasks/
  lib/templates/
  db/
  spec/
  test/
  tmp/

Previously, if any part of the path matched (e.g. db matching cool-db-adapter), it would get skipped.

Additionally, log used to be a skipped path which would match paths like catalog.

This has been fixed to only skip paths with an exact match.

(changes)

More Deserialization Warnings

Brakeman will now warn about all uses of Marshal.load or Marshal.restore.

This may be a little noisy, so please feel free to provide feedback on false positives.

(changes)

More Eval Warnings

Brakeman will now warn about evaluation of dynamic strings, even if there is no obvious user-controllable input.

In addition, Brakeman will warn about most uses of eval.

This may be a little noisy, so please feel free to provide feedback on false positives.

(changes)

SARIF Reports

SARIF reports output from Brakeman will now include the originalBaseUriIds property to enable using of absolute file paths inside of the report. This should enhance compatibility with GitHub and other tools.

See the (changes) for details of how this interacts with scan paths.

Step for Finding Files

For large applications, just listing out relevant files for Brakeman to scan can take some time.

This step was previously “invisible” but now Brakeman will output Finding files... as a descrete step which also means it will work with the --timing option to display how long that step takes.

(changes)

Dependency Updates

Brakeman no longer restricts terminal-table to an old version.

(changes)

csv is now an explicit dependency since it has moved to a bundled gem in Ruby 3.4.

(changes)

The minimum Ruby version to run Brakeman is now Ruby 3.1.0.

(changes)

Checksums

The SHA256 sums for this release are:

1a0122b0c70f17519a61548a53a332c0acc19e3aa10b445e15e025a4b13b8577  brakeman-7.0.0.gem
ecb1a4241df4d3756d0f81b6973852d0390511275a513768aee9ddc398bbfe05  brakeman-lib-7.0.0.gem
6cbe26b0cab0db59bf0a2dd77eb244386f8386d8f7081a8a843469fde6e55367  brakeman-min-7.0.0.gem

Reporting Issues

Thank you to everyone who reported bugs and contributed to this release!

Please report any issues with this release. Take a look at this guide to reporting Brakeman problems.

Hang out on Github for questions and discussion.

Brakeman 6.2.2 Released

Small release!

Changes since 6.2.1:

  • Revamp command injection detection in pipeline* calls (#1862)
  • New end-of-support dates for Rails
  • Exclude more native gems from vendored gems in brakeman gem (#1869)

Command Injection in pipeline_* calls

More specific checks for arguments to Open3 methods pipeline, pipline_r, pipeline_rw, pipeline_w, and pipeline_start to improve both true and false positive rates.

(changes)

Updated End of Support Dates for Rails

Updated based on the updated policy.

Unfortunately, timing of this Brakeman release means Brakeman is already warning about Rails 6.1 end-of-support (ended October 1st).

(changes)

Checksums

The SHA256 sums for this release are:

d502d653699f4d451b21225ff4d19a9ec9345d23eaab5576e246185ffd7bf618  brakeman-6.2.2.gem
fb7ba15cd309f995c95d15d9e0e590f3aad6f95a5dfa030854e8806f3ba196d9  brakeman-lib-6.2.2.gem
b3a5b59a14a527bfaca4d2637765e98c12ae800c8f044b1939da578d3ed31851  brakeman-min-6.2.2.gem

Reporting Issues

Thank you to everyone who reported bugs and contributed to this release!

Please report any issues with this release. Take a look at this guide to reporting Brakeman problems.

Hang out on Github for questions and discussion.

Brakeman 6.2.1 Released

Lots of great contributions in this release, thanks!

Changes since 6.1.2:

What happened to 6.2.0? Packaging issue! No other changes.

Optional Support for Prism Parser

Prism is a new Ruby parsing library which is intended to bring together all the various Ruby parsing libraries together.

This release adds optional support for the Prism parser.

To enable use of Prism, install it directly or add it to your Gemfile. Then enable it with --prism.

(changes)

Parallel Assignment with Splats

Support splats in parallel assignments like

a, *b = 1, 2, 3

(changes)

Unscoped Finds with find_by!

Warn about insecure direct object references in code using find_by!:

User.find_by!(id: params[:id])

(changes)

Initial Rails 8 Support

While there is no specific behavior added yet for Rails 8, Brakeman will detect it properly and the -8/--rails8 options have been added.

Thanks to Ron Shinall for proactively adding this functionality.

(changes)

Thanks to Lu Zhu, Brakeman will now follow symbolic links for directories - in particular links to files outside of the root directory of the Rails application.

(changes)

YAML Aliases in Secrets Config

Chedli Bourguiba enabled support for use of aliases in secrets configuration files.

(changes)

Option to Show Ignored Warnings in Text Report

In response to this request, Gabriel Arcangel Zayas added the --show-ignored option to list ignored warnings in the default text report.

Ignored warnings in text report

(changes)

Top-Level Constants

While it may be semantically incorrect, Brakeman will now treat ::Foo and Foo the same. This helps when matching against known constants like ViewComponent::Base and ::ViewComponent::Base. Thanks to Jill Klang for addressing this one.

(changes)

Remediation Advice for Command Injection

Nicholas Barone added a note about using shellescape to make shell commands safer.

(changes)

Frozen String Support

(Jean Boussier) has made Brakeman compatible with use of Ruby’s frozen string literals (e.g. --enable-frozen-string-literal), avoiding any future issues if/when frozen strings are the default.

Along the way, they also fixed up some Ruby warnings in the test suite.

(changes)

Checksums

The SHA256 sums for this release are:

862e709caa1abf00dd0c47045682404c349f64876c7be74a8e6a4d6be5f61a1d  brakeman-6.2.1.gem
7c3b5268a83d53069b778056624e5f215d17f24902ca7f381299c2ba7dc7b684  brakeman-lib-6.2.1.gem
cb839d5f1e0d356c33141dda377f401712a89e4d501748f1c01faa41c9d0f70e  brakeman-min-6.2.1.gem

Reporting Issues

Thank you to everyone who reported bugs and contributed to this release!

Please report any issues with this release. Take a look at this guide to reporting Brakeman problems.

Hang out on Github for questions and discussion.

Brakeman 6.1.2 Released

Finally, just a small release!

Changes since 6.1.1:

  • Avoid detecting Phlex components as dynamic render paths (Máximo Mussini)
  • Avoid detecting ViewComponentContrib::Base as dynamic render paths (vividmuimui)
  • Avoid copying Sexps that are too large (#1818, #1546)
  • Add EOL date for Ruby 3.3.0
  • Remove deprecated use of Kernel#open("|...")
  • Remove safe_yaml gem dependency
  • Update Highline to 3.0 (#1812)

Components in Render Paths

Thanks to Máximo Mussini and vividmuimui, there will be fewer false positives warning about dynamic render paths when using components.

(changes)

(changes)

Performance Improvement with Complex Branching

Brakeman has a very hard time with code like

x = thing
x = foo(x)

if x
    x = bar(x)
else
    x = baz(x)
end

x = do_thing(x)

# etc.

Because to Brakeman it looks like

x = thing
x = foo(thing)

if foo(thing)
    x = bar(foo(thing))
else
    x = baz(foo(thing))
end

x = do_thing(bar(foo(thing)) || baz(foo(thing)))

This can quickly snowball into gigantic chunks of code, causing Brakeman to use lots of memory and essentially freeze up.

In the past, limits on how many times a value is “branched” have helped with this (and is configurable with --branch-limit). However, it is not sufficient.

Now Brakeman has a limit on how large these chunks of code can get. This has improved performance without any noticable impact on true positives.

(changes)

Checksums

The SHA256 sums for this release are:

7716769c18f2c4a52d7a74d2cb5a614be0c46d8aad3fbe7ca089dbb7c98bd4d3  brakeman-6.1.2.gem
38939998eb695b82932c207ef766356bc21e57199e18c4d8f000a005d294e587  brakeman-lib-6.1.2.gem
dbc2f9a3b61760c03737cf701f5a1dfe634fb14e8388968e056a0f77effab018  brakeman-min-6.1.2.gem

Reporting Issues

Thank you to everyone who reported bugs and contributed to this release!

Please report any issues with this release. Take a look at this guide to reporting Brakeman problems.

Hang out on Github for questions and discussion.

Brakeman 6.1.0 Released

It’s been a while!

Changes since 6.0.1:

  • Add check for unfiltered search with Ransack
  • Add --timing to add timing duration for scan steps
  • Add PG::Connection.escape_string as a SQL sanitization method (Joévin Soulenq)
  • Handle class << self
  • Fix class method lookup in parent classes
  • Fix keyword splats in filter arguments

Ransack Searches

Ransack is a popular library for enabling search against ActiveRecord attributes.

It was originally intended for administrative interfaces (like those provided by ActiveAdmin).

Use usually looks like

Car.ransack(params[:q])

And a url might look like

example.com?q[make_start]=vol

This might generate a query like

SELECT make FROM cars WHERE make LIKE 'vol%';

The library does clever things with the query parameter key. In this case, make is the column and start means match values that start with the search term passed in.

However, it’s also possible to specify columns on related tables, such as

example.com?q[owner_name_start]=just

Which would search the name column on the owners table (assuming Car has an association to Owner).

Prior to Ransack 4.0, the default configuration allowed searching all columns on a table as well as all columns on associated tables.

Some folks figured out this can be used to extract secret values by brute-forcing the value one character at a time.

To fix this issue, explicitly allow list the attributes and associations available to search.

In Ransack 4.0 and later, it is required to set up an allowlist.

Brakeman will warn about unrestricted use of ransack:

  • High if no allow-listing methods are found in the class hierarchy of the model on which ransack is called
  • Medium if the use happens to be in a file with admin in the path
  • Low if the call to ransack is not on a class

(changes)

Timing Output

Use --timing to output duration of various steps during the scan.

Useful for debugging slowness.

(changes)

Another SQL Escaping Method

Brakeman will not warn about use of escape_string in SQL queries.

(changes)

Class Methods

Brakeman will now treat methods defined inside of class << self as class methods.

This does mean fingerprints of warnings found inside those methods will change.

(changes)

Class Method Lookups

Searching for class method definitions in parent classes will now actually look for class methods, not instance methods.

(changes)

Keyword Splats in Filters

Code like

before_action(**kwargs) do
  # ...
end

Will no longer cause an error.

(changes)

Checksums

The SHA256 sums for this release are:

0d4066936dd58f0fe757d0ff1ec0744479be9ff06c771be4b581bdf0cb8d7403  brakeman-6.1.0.gem
e7c9e739a43ec719d981e9b401b980c11cbe81a333ccb166965b9264ef413cc8  brakeman-lib-6.1.0.gem
709813eff010c9605dc09b9fcbe60742dd3b9e757ec7131808988a14b83eee23  brakeman-min-6.1.0.gem

Reporting Issues

Thank you to everyone who reported bugs and contributed to this release!

Please report any issues with this release. Take a look at this guide to reporting Brakeman problems.

Hang out on Github for questions and discussion.