Skip to content

Commit

Permalink
Merge branch 'main' into use_prism
Browse files Browse the repository at this point in the history
  • Loading branch information
presidentbeef committed Jul 6, 2024
2 parents eee414e + 7f673cd commit fd7dd01
Show file tree
Hide file tree
Showing 61 changed files with 1,064 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Using Bundler:

```ruby
group :development do
gem 'brakeman'
gem 'brakeman', require: false
end
```

Expand Down
4 changes: 4 additions & 0 deletions docs/warning_types/command_injection/index.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ There are many ways to run commands in Ruby:

Brakeman will warn on any method like these that uses user input or unsafely interpolates variables.

You can use [`shellescape`](https://apidock.com/ruby/Shellwords/shellescape) to render a variable safe:

`ls #{params[:file].shellescape}`

See [the Ruby Security Guide](http://guides.rubyonrails.org/security.html#command-line-injection) for details.
1 change: 1 addition & 0 deletions gem_common.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Brakeman
module GemDependencies
def self.dev_dependencies spec
spec.add_development_dependency "csv"
spec.add_development_dependency "minitest"
spec.add_development_dependency "minitest-ci"
spec.add_development_dependency "simplecov"
Expand Down
2 changes: 1 addition & 1 deletion lib/brakeman/checks/check_session_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def check_secrets_yaml
yaml = secrets_file.read
require 'yaml'
begin
secrets = YAML.safe_load yaml
secrets = YAML.safe_load yaml, aliases: true
rescue Psych::SyntaxError, RuntimeError => e
Brakeman.notify "[Notice] #{self.class}: Unable to parse `#{secrets_file}`"
Brakeman.debug "Failed to parse #{secrets_file}: #{e.inspect}"
Expand Down
9 changes: 9 additions & 0 deletions lib/brakeman/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ def create_option_parser options
options[:rails7] = true
end

opts.on "-8", "--rails8", "Force Rails 8 mode" do
options[:rails3] = true
options[:rails4] = true
options[:rails5] = true
options[:rails6] = true
options[:rails7] = true
options[:rails8] = true
end

opts.separator ""
opts.separator "Scanning options:"

Expand Down
2 changes: 2 additions & 0 deletions lib/brakeman/parsers/slim_embedded.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
module Slim
class Embedded
class TiltEngine
alias_method :on_slim_embedded, :on_slim_embedded # silence redefined method warning
def on_slim_embedded(engine, body, attrs)
# Override this method to avoid Slim trying to load sass/scss and failing
case engine
Expand All @@ -22,6 +23,7 @@ def on_slim_embedded(engine, body, attrs)
class SassEngine
protected

alias_method :tilt_render, :tilt_render # silence redefined method warning
def tilt_render(tilt_engine, tilt_options, text)
[:dynamic,
"BrakemanFilter.render(#{text.inspect}, #{self.class})"]
Expand Down
45 changes: 33 additions & 12 deletions lib/brakeman/processors/alias_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ def process_masgn exp
exp[2] = exp[2][1]
end

unless array? exp[1] and array? exp[2] and exp[1].length == exp[2].length
unless array? exp[1] and array? exp[2]
return process_default(exp)
end

Expand All @@ -678,21 +678,42 @@ def process_masgn exp
# Call each assignment as if it is normal
vars.each_with_index do |var, i|
val = vals[i]
if val
next unless val # TODO: Break if there are no vals left?

# This happens with nested destructuring like
# x, (a, b) = blah
if node_type? var, :masgn
# Need to add value to masgn exp
m = var.dup
m[2] = s(:to_ary, val)
# This happens with nested destructuring like
# x, (a, b) = blah
if node_type? var, :masgn
# Need to add value to masgn exp
m = var.dup
m[2] = s(:to_ary, val)

process_masgn m
process_masgn m
elsif node_type? var, :splat
# Assign the rest of the values to the variable:
#
# a, *b = 1, 2, 3
#
# b == [2, 3]


assign = var[1].dup # var is s(:splat, s(:lasgn, :b))

if i == vars.length - 1 # Last variable being assigned, slurp up the rest
assign.rhs = s(:array, *vals[i..]) # val is the "rest" of the values
else
assign = var.dup
assign.rhs = val
process assign
# Calculate how many values to assign based on how many variables
# there are.
#
# If there are more values than variables, the splat gets an empty array.

assign.rhs = s(:array, *vals[i, (vals.length - vars.length + 1)]).line(vals.line)
end

process assign
else
assign = var.dup
assign.rhs = val
process assign
end
end

Expand Down
10 changes: 9 additions & 1 deletion lib/brakeman/tracker/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ def set_rails_version version = nil
tracker.options[:rails6] = true
tracker.options[:rails7] = true
Brakeman.notify "[Notice] Detected Rails 7 application"
elsif @rails_version.start_with? "8"
tracker.options[:rails3] = true
tracker.options[:rails4] = true
tracker.options[:rails5] = true
tracker.options[:rails6] = true
tracker.options[:rails7] = true
tracker.options[:rails8] = true
Brakeman.notify "[Notice] Detected Rails 8 application"
end
end
end
Expand Down Expand Up @@ -193,7 +201,7 @@ def load_rails_defaults

version = tracker.config.rails[:load_defaults].value.to_s

unless version.match? /^\d+\.\d+$/
unless version.match?(/^\d+\.\d+$/)
Brakeman.debug "[Notice] Unknown version: #{tracker.config.rails[:load_defaults]}"
return
end
Expand Down
6 changes: 5 additions & 1 deletion lib/ruby_parser/bm_sexp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Sexp
ASSIGNMENT_BOOL = [:gasgn, :iasgn, :lasgn, :cvdecl, :cvasgn, :cdecl, :or, :and, :colon2, :op_asgn_or]
CALLS = [:call, :attrasgn, :safe_call, :safe_attrasgn]

alias_method :method_missing, :method_missing # silence redefined method warning
def method_missing name, *args
#Brakeman does not use this functionality,
#so overriding it to raise a NoMethodError.
Expand Down Expand Up @@ -46,10 +47,12 @@ def deep_clone line = nil
s
end

alias_method :paren, :paren # silence redefined method warning
def paren
@paren ||= false
end

alias_method :value, :value # silence redefined method warning
def value
raise WrongSexpError, "Sexp#value called on multi-item Sexp: `#{self.inspect}`" if size > 2
self[1]
Expand Down Expand Up @@ -98,6 +101,7 @@ def << arg
old_push arg
end

alias_method :hash, :hash # silence redefined method warning
def hash
#There still seems to be some instances in which the hash of the
#Sexp changes, but I have not found what method call is doing it.
Expand Down Expand Up @@ -616,7 +620,7 @@ def inspect seen = Set.new

#Invalidate hash cache if the Sexp changes
[:[]=, :clear, :collect!, :compact!, :concat, :delete, :delete_at,
:delete_if, :drop, :drop_while, :fill, :flatten!, :replace, :insert,
:delete_if, :drop, :drop_while, :fill, :flatten!, :insert,
:keep_if, :map!, :pop, :push, :reject!, :replace, :reverse!, :rotate!,
:select!, :shift, :shuffle!, :slice!, :sort!, :sort_by!, :transpose,
:uniq!, :unshift].each do |method|
Expand Down
34 changes: 34 additions & 0 deletions test/apps/rails5.2/config/secrets.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.

# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

test_anchor: &test_anchor
abc: 123

development:
test_anchor: *test_anchor
secret_key_base: 12d3735e1cdb18ef2eca25f9a370028ac096ff273c5a889ed7a49047d5e30c9dc7fe095792a71b60c3f37dd80efaeda44db75e73c9f60813550c875eee7a241f

test:
test_anchor: *test_anchor
secret_key_base: 446b08c3cdeccdaf9e8b247a2624d45218c5d429e8acde61ddd87aa7b9dd50973e49e6d94378cb4bcf08b7818a90abb044b5c8886f94de6970ade4a496df22f3

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
test_anchor: *test_anchor
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

<% if Rails.root.join('config/ansible/secrets.yml').exist? %>
<%= Rails.root.join('config/ansible/secrets.yml').read %>
<% end %>


54 changes: 54 additions & 0 deletions test/apps/rails8/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
source "https://rubygems.org"

# Use main development branch of Rails
gem "rails", "~> 8.0.0.alpha", github: "rails/rails", branch: "main"
# The modern asset pipeline for Rails [https://github.com/rails/propshaft]
gem "propshaft"
# Use sqlite3 as the database for Active Record
gem "sqlite3", ">= 1.4"
# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"
# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"
# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"
# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"
# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"
# Use Redis adapter to run Action Cable in production
gem "redis", ">= 4.0.1"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Deploy this application anywhere as a Docker container [https://kamal-deploy.org]
# gem "kamal", require: false

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"

# Static analysis for security vulnerabilities [https://brakemanscanner.org/]
# gem "brakeman", require: false

# Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
# gem "rubocop-rails-omakase", require: false
end

group :development do
# Use console on exceptions pages [https://github.com/rails/web-console]
gem "web-console"
end
1 change: 1 addition & 0 deletions test/apps/rails8/app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* Application styles */
4 changes: 4 additions & 0 deletions test/apps/rails8/app/channels/application_cable/channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
4 changes: 4 additions & 0 deletions test/apps/rails8/app/channels/application_cable/connection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module ApplicationCable
class Connection < ActionCable::Connection::Base
end
end
4 changes: 4 additions & 0 deletions test/apps/rails8/app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class ApplicationController < ActionController::Base
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
allow_browser versions: :modern
end
2 changes: 2 additions & 0 deletions test/apps/rails8/app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module ApplicationHelper
end
3 changes: 3 additions & 0 deletions test/apps/rails8/app/javascript/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"
9 changes: 9 additions & 0 deletions test/apps/rails8/app/javascript/controllers/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Application } from "@hotwired/stimulus"

const application = Application.start()

// Configure Stimulus development experience
application.debug = false
window.Stimulus = application

export { application }
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
connect() {
this.element.textContent = "Hello World!"
}
}
11 changes: 11 additions & 0 deletions test/apps/rails8/app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Import and register all your controllers from the importmap under controllers/*

import { application } from "controllers/application"

// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)

// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
// lazyLoadControllersFrom("controllers", application)
7 changes: 7 additions & 0 deletions test/apps/rails8/app/jobs/application_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class ApplicationJob < ActiveJob::Base
# Automatically retry jobs that encountered a deadlock
# retry_on ActiveRecord::Deadlocked

# Most jobs are safe to ignore if the underlying records are no longer available
# discard_on ActiveJob::DeserializationError
end
4 changes: 4 additions & 0 deletions test/apps/rails8/app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: "from@example.com"
layout "mailer"
end
3 changes: 3 additions & 0 deletions test/apps/rails8/app/models/application_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
end
24 changes: 24 additions & 0 deletions test/apps/rails8/app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || "My App" %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= yield :head %>

<link rel="manifest" href="/manifest.json">
<link rel="icon" href="/icon.png" type="image/png">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/icon.png">

<%= stylesheet_link_tag :all, "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
</head>

<body>
<%= yield %>
</body>
</html>
13 changes: 13 additions & 0 deletions test/apps/rails8/app/views/layouts/mailer.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
/* Email styles need to be inline */
</style>
</head>

<body>
<%= yield %>
</body>
</html>
1 change: 1 addition & 0 deletions test/apps/rails8/app/views/layouts/mailer.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= yield %>
Loading

0 comments on commit fd7dd01

Please sign in to comment.