Brakeman

Ruby on Rails Static Analysis Security Tool

Brakeman 5.1.0 Released

This is a huge release! (So many changes, I had to look up how to nest lists in Markdown…)

Thank you to the many contributors!

There are several new features, take a look below.

Changes since 5.0.4:

  • Report Formats
  • Performance
    • Read and parse files in parallel
  • Ruby Interpretation
    • Initial support for ActiveRecord enums (#1492)
    • Interprocedural dataflow from very simple class methods
    • Support Array#fetch and Hash#fetch (#1571)
    • Support Array#push
    • Support Array#*
    • Better Array#join support
    • Support Hash#values and Hash#values_at
    • Support Hash#include?
  • SQL Injection
    • Update SQL injection check for Rails 6.0/6.1
    • Add --sql-safe-methods option (Esty Scheiner)
    • Ignore dates in SQL
    • Ignore sanitize_sql_like in SQL (#1571)
    • Ignore method calls on numbers in SQL (#1571)
  • Other Fixes
    • Ignore renderables in dynamic render path check (Brad Parker)
    • Fix false positive in command injection with Open3.capture (Richard Fitzgerald)
    • Fix infinite loop on mixin self-includes (Andrew Szczepanski)
    • Check for user-controlled evaluation even if it’s a call target (#1590)
  • Refactoring
    • Refactor cookie?/param? methods (Keenan Brock)
    • Better method definition tracking and lookup

Report Formats

Klaus Badelt added support for GitHub Actions annotation format with -f github.

(changes)

Eli Block added support for reporting ignored warnings in SARIF using the “suppressed” property and fixed a SARIF bug.

(changes)

Elia Schito clarified some text in the --interactive menu for ignoring warnings.

(changes)

Parallel File Parsing

Brakeman now uses the parallel gem to read and parse files in parallel.

By default, parallel will split the reading/parsing into a number of separate processes based on number of CPUs.

In testing, this has dramatically improved speed for large code bases - around 35% reduction in overall scan time.

However, if you run into weird behavior (e.g. scanning just hangs during file parsing), this feature can be disabled using --no-threads.

(changes)

Ruby Interpretation

Simple Class Methods

Brakeman will now track and return very simple literal values (e.g. strings, hashes of literals, arrays of literals) from very simple class methods (e.g. single line).

For example:

class User
  def self.path_prefix
    '/user'
  end
end

User.path_prefix # => '/user'

This should help prevent some false positives.

Enums

Since ActiveRecord enums essentially generate some class (and instance) methods that return fixed literal values, the above class method return values is also used to support enum.

For example:

class User < ActiveRecord::Base
  enum status: [:pending, :active, :locked]
end

User.statuses[:pending] # => 0

(changes)

Hash and Array Methods

In some ways, Brakeman is a very poor Ruby interpreter. To “understand” the code it analyzes, Brakeman essentially evaluates some methods. This release adds and improves support for evaluating a number of Hash and Array methods.

  • Support Array#fetch and Hash#fetch (changes)
  • Support Array#push (changes)
  • Support Array#* and improve Array#join (changes)
  • Support Hash#values and Hash#values_at (changes)
  • Support Hash#include? (changes)

SQL Injection

Updates for Rails 6.0/6.1

Some new Rails 6.0 methods were previously added for SQL injection (destroy_by/delete_by), but this release is more thorough.

Newly vulnerable methods:

  • reselect
  • rewhere

No longer vulnerable:

  • delete_all
  • destroy_all
  • pluck (in Rails 6.1)

Not really vulnerable:

  • order (in Rails 6.1)
  • reorder (in Rails 6.1)

(Also, [https://rails-sqli.org/] has also been updated with Rails 6 information!)

(changes)

Safe Methods

Esty Scheiner added the --sql-safe-methods option to ignore some methods when checking for SQL injection.

(changes)

False Positives

Brakeman no longer warns about SQL injection for:

  • Dates and methods called on dates (changes)
  • Method calls on number literals (changes)
  • sanitize_sql_like (changes)

Misc Fixes

Brad Parker updated the dynamic render path check to ignore “renderables”.

(changes)

Richard Fitzgerald fixed a command injection false positive when using Open3.capture.

(changes)

Andrew Szczepanski fixed an infinite loop when a mixin appears to include itself.

(changes)

Brakeman will now warn about user-controlled evaluation even if the evaluation is a call target itself.

For example:

eval(params[:debug]).do_something_else

(changes)

Refactoring

Keenan Brock cleaned up the cookie?/param? utility methods.

(changes)

In support of enum and simple class methods, Brakeman now has a cleaner way of tracking and looking up method definitions.

(changes)

New and Updated Options

--sql-safe-methods can be used to specify methods that should be ignored in the context of SQL injection.

--format github/-f github will output code the annotation format used by GitHub Actions.

--no-threads/-n will disable use of threads (actually forked processes) for reading and parsing files. (Previously, this method only disabled use of threads when running checks.)

Checksums

The SHA256 sums for this release are:

2cc7a174bc9ebb90161f218ea35905de8d749210f69a0bfda9fba71429dc5047  brakeman-5.1.0.gem
b8182c9fd7d6d116b2b531c5d8fe0bf9c8da14118b755ed00be8de8c4684ad10  brakeman-lib-5.1.0.gem
e38ff386530bc5585e2efd183ba73c08abb740c3b26072662025a3d9395b707a  brakeman-min-5.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.

Follow @brakeman on Twitter and hang out on Gitter for questions and discussion.

Brakeman 5.0.4 Released

This is a tiny bugfix release!

What happened to 5.0.2 and 5.0.3??

They were messed up. Sorry. Don’t use them.

Changes since 5.0.1:

  • Fix Loofah version check (#1603)

Checksums

The SHA256 sums for this release are:

4d1af5c3e65a0c2319396a796bd9a587a13317faff92bd09b74c44ba70aef8b3  brakeman-5.0.4.gem
6b529ae8f1e16aed711759c3b52fc01c60befeb896042de02aaa5aabf5c24cb5  brakeman-lib-5.0.4.gem
5a402076af48fc526211212d70a751c80c27cae535077c1c7a63dadc314efe97  brakeman-min-5.0.4.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.

Follow @brakeman on Twitter and hang out on Gitter for questions and discussion.

Brakeman 5.0.1 Released

Has it really been three months since Brakeman 5.0? Yikes!

Here’s a small update with some bugfixes before we move on to 5.1.

Changes since 5.0.0:

  • Support loading slim/smart (#1570)
  • Set more line numbers on Sexps (#1579)
  • Detect ::Rails.application.configure too (#1584)
  • Always ignore slice/only calls for mass assignment
  • Don’t fail if $HOME/$USER are not defined
  • Convert splat array arguments to arguments
  • Bundle unreleased RubyParser changes

Support Smart Text in Slim Templates

In order to support “Smart Text” in Slim templates, Brakeman will load slim/smart if slim/smart is mentioned in the Gemfile.

(changes)

More Line Numbers

Setting nil value for the line number of a Sexp raises an exception.

This is usually from creating a Sexp without a line number in the first place.

More instances of this have been fixed in this release.

(changes)

Always Ignore slice/only for Mass Assignment

If slice or only are called for arguments to mass assignment (e.g. User.new(some_hash.slice(:name, :email))), Brakeman will not warn about mass assignment.

These have been ignored for a while, but a logic error caused Brakeman to sometimes still warn about them.

(changes)

Convert Splats to Arguments

In really obvious cases like

some_call(*[a, b, c])

Brakeman will convert the arguments to

some_call(a, b, c)

(changes)

Checksums

The SHA256 sums for this release are:

4c1b7c7747ecfca11a822a4bab5ad05f13515e195d7d34590d3add215573b431  brakeman-5.0.1.gem
79129c2977936113fc87a9a2e9490b734f088286d0b33ed9ca61cb6587dc18c7  brakeman-lib-5.0.1.gem
549034d7aeb2a5ca8fe299c41b91938d502a89e70a1afa68643ca3c9e5ccaf96  brakeman-min-5.0.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.

Follow @brakeman on Twitter and hang out on Gitter for questions and discussion.

Brakeman 5.0.0 Released

It has been a long time coming, but it is finally here! Lots of changes in this one…

Brakeman now scans (almost) all Ruby (and ERB, Haml, Slim) files in an application. This may have a significant impact on reported warnings and scan times - see below for more information.

Changes since 4.10.1:

  • Scan (almost) all Ruby files in project
  • Revamp CSV report to a CSV list of warnings
  • Add Sonarqube report format (Adam England)
  • Add check for (more) unsafe method reflection (#1488, #1507, and #1508)
  • Add check for potential HTTP verb confusion (#1432)
  • Add --[no-]skip-vendor option
  • Ignore uuid as a safe attribute
  • Ignore Tempfile#path in shell commands
  • Ignore development environment
  • Collapse __send__ calls
  • Set Rails configuration defaults based on load_defaults version
  • Update Ruby requirement to version 2.4.0
  • Suggest using --force if no Rails application is detected

Scan Almost All Ruby Files

Since the beginning, Brakeman has been picky about what directories it searches for files. In general, Brakeman has looked in ‘normal’ Rails directores like app/controllers/, app/models/, app/views/, lib/, config, etc. This is because Rails has some default logic based on file paths - like mapping a controller action to a given view.

But if an application varied from the norm, Brakeman would simply not scan those other directories. This behavior led to a lot of confusion with folks wondering why Brakeman was not finding certain vulnerabilities.

Brakeman now attempts to deduce the contents of a file first, then falls back to the path name if necessary. This has been surprisingly effective.

However, scanning more files means Brakeman runs slower and may report more false positives because the new files are harder to reason about and less likely to be exposed as part of the attack surface.

Brakeman does ignore test, spec, and vendor directories. To scan the vendor directory as well, use --no-skip-vendor.

Please report any issues!

(changes)

CSV Report Update

The CSV report format has been completely changed! Previously, it was meant as an ‘Excel-lite’ format, only really useful for viewing in a spreadsheet program.

Now it is regular CSV with normalized columns to mostly match the JSON report (except for nested fields).

(changes)

Sonarqube Report Format

Thanks to Adam England, Brakeman now supports the Sonarqube “Generic Issue Import Format”.

(And thanks Adam for your patience.)

(changes)

More Unsafe Method Reflection

A new check was added for unsafe use of method, to_proc, and tap.

(changes)

HTTP Verb Confusion Check

In Rails, HEAD requests are routed like GET requests, but request.get? will be false.

Some code may assume if request.get? is false, then request.post? is true:

if request.get?
  # Do something benign
else
  # Do something sensitive because it's a POST
  # but actually it could be a HEAD :(
end

Brakeman will warn when an if expression checks request.get? but has an else clause instead of elseif ....

(changes)

UUIDs as Safe Attributes

#uuid will be treated as a safe value, particular in SQL.

(changes)

Tempfile Paths in Shell Commands

Tempfile#path will be considered as safe value for command injection.

Also adds support for Tempfiles like:

Tempfile.open('...') do |file|
  # Brakeman knows `file` is a Tempfile
end

(changes

Ignore Development Environment

Brakeman will ignore code that is guarded like

if Rails.env.development?
  # ...whatever code
end

This was already true for Rails.env.test?.

(changes)

Collapse __send__ Calls

Brakeman will treat

Blah.__send__(:something, 5.0)

as

Blah.something(5.0)

This was already true for send and try.

(changes)

Set Rails Defaults

Brakeman will set default values for Rails configuration options based on the version argument to config.load_defaults which is usually called in application.rb.

(changes)

Requires Ruby 2.4.0

The minimal Ruby version for running Brakeman is now 2.4.0 (which is already EOL!)

Note Brakeman can analyze Ruby syntax from 1.8 to 2.6 (some 2.7+ syntax is not supported yet).

(changes)

Checksums

The SHA256 sums for this release are:

21b91f67cde4cf487df0a4dbf6e54729064c665bb0b4b370b71bac9435b63e4c  brakeman-5.0.0.gem
3641c52448ca1d12423595ca1a874c1362f438cd58196825be648bb797096cb5  brakeman-lib-5.0.0.gem
50bab26fe8fcf8d962baaf5b08b7c178315b7c0e4be07d1b134e8ae00338c908  brakeman-min-5.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.

Follow @brakeman on Twitter and hang out on Gitter for questions and discussion.

Brakeman 4.10.1 Released

This releases fixes Ruby 3.0 compatibility (meaning running under 3.0, new syntax is not supported yet).

Changes since 4.10.0:

  • Declare REXML as a dependency (Ruby 3.0 compatibility)
  • Use Sexp#sexp_body instead of Sexp#[..] (Ruby 3.0 compatibility)
  • Prevent render loops when template names are absolute paths (#1536)
  • Ensure RubyParser is passed file path as a String (#1534)
  • Support new Haml 5.2.0 escaping method (#1517)

REXML as an Explicit Dependency

In Ruby 3.0, REXML has become a ‘bundled’ gem. It is distributed with Ruby, but if Bundler is involved then it needs to be declared as an explicit dependency.

If you like minimal dependencies, you can always use the brakeman-min gem which declares only strict dependencies.

(changes)

Avoid Slicing with Sexp#[]

Sexp subclasses from Array, and Array no longer returns subclasses from methods that create new arrays.

Brakeman was unfortunately using Sexp#[] with ranges (e.g. s(:a, :b, :c)[1..-1]), which runs into this behavior. Happily, the Sexp#sexp_body method already exists to properly slice and return a Sexp.

(changes)

Recursive Renders with Absolute Paths

Brakeman has long been able to detect recursive render loops, but that detection did not work if the partial name was an ‘absolute’ path.

This is now fixed!

(changes)

Ensure RubyParser Path is a String

In some cases, the parser was given a Brakeman::FilePath for the file name. This only caused an issue in some weird corner cases, but it was wrong nonetheless.

Now Brakeman::FileParser will ensure the file name is passed as a string.

(changes)

Support Haml 5.2

Haml 5.2.0 introduced a new method for escaping output, which caused some false positives.

(Note this was avoided in Brakeman 4.10.0 by bundling an earlier version of Haml.)

(changes)

Checksums

The SHA256 sums for this release are:

e40451080554884a63d73a2933c36518a3cf7a2bb471e6d864ce39a9d3455c98  brakeman-4.10.1.gem
ec69e04e087b74862629e952d7817dd7b73e30810166e01d69d24d7164101455  brakeman-lib-4.10.1.gem
3deee68eadd8eb6850254a8e753d6bbe933194c883f12a2455bdf5fd97b1eba2  brakeman-min-4.10.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.

Follow @brakeman on Twitter and hang out on Gitter for questions and discussion.