tainted_love 0.1.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +2 -0
- data/bin/setup +3 -3
- data/bin/test +6 -2
- data/dev.yml +1 -1
- data/lib/tainted_love.rb +2 -2
- data/lib/tainted_love/replacer/base.rb +5 -1
- data/lib/tainted_love/replacer/replace_action_controller.rb +0 -4
- data/lib/tainted_love/replacer/replace_active_record.rb +21 -1
- data/lib/tainted_love/replacer/replace_graphql.rb +27 -0
- data/lib/tainted_love/replacer/replace_kernel.rb +1 -1
- data/lib/tainted_love/replacer/replace_object.rb +8 -2
- data/lib/tainted_love/replacer/replace_rack_builder.rb +51 -0
- data/lib/tainted_love/replacer/replace_rack_file.rb +25 -0
- data/lib/tainted_love/replacer/replace_rack_query_parser.rb +50 -0
- data/lib/tainted_love/replacer/replace_rails_user_input.rb +12 -27
- data/lib/tainted_love/replacer/replace_string.rb +69 -0
- data/lib/tainted_love/replacer/replace_tag_builder.rb +16 -0
- data/lib/tainted_love/reporter/base.rb +4 -1
- data/lib/tainted_love/reporter/stdout_reporter.rb +1 -0
- data/lib/tainted_love/utils.rb +4 -19
- data/lib/tainted_love/utils/proxy.rb +95 -0
- data/lib/tainted_love/validator/action_dispatch_diagnostics.rb +20 -0
- data/lib/tainted_love/validator/active_record_find.rb +15 -0
- data/lib/tainted_love/validator/erb_eval.rb +1 -3
- data/lib/tainted_love/validator/haml_eval.rb +25 -0
- data/lib/tainted_love/validator/i18n_load.rb +17 -0
- data/lib/tainted_love/validator/ignore.rb +21 -0
- data/lib/tainted_love/version.rb +1 -1
- data/service.yml +6 -0
- data/{example → tests/rails}/.gitignore +0 -0
- data/{example → tests/rails}/.ruby-version +0 -0
- data/{example → tests/rails}/Gemfile +5 -4
- data/{example → tests/rails}/Gemfile.lock +29 -32
- data/{example → tests/rails}/README.md +0 -0
- data/{example → tests/rails}/Rakefile +0 -0
- data/{example → tests/rails}/app/assets/config/manifest.js +0 -0
- data/{example → tests/rails}/app/assets/images/.keep +0 -0
- data/{example → tests/rails}/app/assets/javascripts/application.js +0 -0
- data/{example → tests/rails}/app/assets/javascripts/cable.js +0 -0
- data/{example → tests/rails}/app/assets/javascripts/channels/.keep +0 -0
- data/{example → tests/rails}/app/assets/javascripts/products.coffee +0 -0
- data/{example → tests/rails}/app/assets/stylesheets/application.css +0 -0
- data/{example → tests/rails}/app/assets/stylesheets/products.scss +0 -0
- data/{example → tests/rails}/app/assets/stylesheets/scaffolds.scss +0 -0
- data/{example → tests/rails}/app/channels/application_cable/channel.rb +0 -0
- data/{example → tests/rails}/app/channels/application_cable/connection.rb +0 -0
- data/{example → tests/rails}/app/controllers/application_controller.rb +0 -0
- data/{example → tests/rails}/app/controllers/concerns/.keep +0 -0
- data/tests/rails/app/controllers/graphql_controller.rb +43 -0
- data/{example → tests/rails}/app/controllers/products_controller.rb +0 -0
- data/tests/rails/app/controllers/test_cases_controller.rb +43 -0
- data/tests/rails/app/graphql/example_schema.rb +4 -0
- data/{example/app/models/concerns → tests/rails/app/graphql/mutations}/.keep +0 -0
- data/{example/lib/assets → tests/rails/app/graphql/types}/.keep +0 -0
- data/tests/rails/app/graphql/types/base_enum.rb +4 -0
- data/tests/rails/app/graphql/types/base_input_object.rb +4 -0
- data/tests/rails/app/graphql/types/base_interface.rb +5 -0
- data/tests/rails/app/graphql/types/base_object.rb +4 -0
- data/tests/rails/app/graphql/types/base_scalar.rb +4 -0
- data/tests/rails/app/graphql/types/base_union.rb +4 -0
- data/tests/rails/app/graphql/types/mutation_type.rb +10 -0
- data/tests/rails/app/graphql/types/product_type.rb +10 -0
- data/tests/rails/app/graphql/types/query_type.rb +46 -0
- data/tests/rails/app/graphql/types/taint_test_case_input.rb +8 -0
- data/{example → tests/rails}/app/helpers/application_helper.rb +0 -0
- data/{example → tests/rails}/app/helpers/products_helper.rb +0 -0
- data/{example → tests/rails}/app/helpers/test_cases_helper.rb +0 -0
- data/{example → tests/rails}/app/jobs/application_job.rb +0 -0
- data/{example → tests/rails}/app/mailers/application_mailer.rb +0 -0
- data/{example → tests/rails}/app/models/application_record.rb +0 -0
- data/{example/lib/tasks → tests/rails/app/models/concerns}/.keep +0 -0
- data/{example → tests/rails}/app/models/product.rb +0 -0
- data/{example → tests/rails}/app/views/layouts/application.html.erb +0 -0
- data/{example → tests/rails}/app/views/layouts/mailer.html.erb +0 -0
- data/{example → tests/rails}/app/views/layouts/mailer.text.erb +0 -0
- data/{example → tests/rails}/app/views/products/_form.html.erb +0 -0
- data/{example → tests/rails}/app/views/products/_product.json.jbuilder +0 -0
- data/{example → tests/rails}/app/views/products/edit.html.erb +0 -0
- data/{example → tests/rails}/app/views/products/index.html.erb +0 -0
- data/{example → tests/rails}/app/views/products/index.json.jbuilder +0 -0
- data/{example → tests/rails}/app/views/products/new.html.erb +0 -0
- data/{example → tests/rails}/app/views/products/show.html.erb +0 -0
- data/{example → tests/rails}/app/views/products/show.json.jbuilder +0 -0
- data/{example → tests/rails}/app/views/test_cases/xss.html.erb +0 -0
- data/{example → tests/rails}/bin/bundle +0 -0
- data/{example → tests/rails}/bin/rails +0 -0
- data/{example → tests/rails}/bin/rake +0 -0
- data/{example → tests/rails}/bin/setup +0 -0
- data/{example → tests/rails}/bin/spring +0 -0
- data/{example → tests/rails}/bin/update +0 -0
- data/{example → tests/rails}/bin/yarn +0 -0
- data/{example → tests/rails}/config.ru +0 -0
- data/{example → tests/rails}/config/application.rb +0 -0
- data/{example → tests/rails}/config/boot.rb +0 -0
- data/{example → tests/rails}/config/cable.yml +0 -0
- data/{example → tests/rails}/config/credentials.yml.enc +0 -0
- data/{example → tests/rails}/config/database.yml +0 -0
- data/{example → tests/rails}/config/environment.rb +0 -0
- data/{example → tests/rails}/config/environments/development.rb +0 -0
- data/{example → tests/rails}/config/environments/production.rb +0 -0
- data/{example → tests/rails}/config/environments/test.rb +0 -0
- data/{example → tests/rails}/config/initializers/application_controller_renderer.rb +0 -0
- data/{example → tests/rails}/config/initializers/assets.rb +0 -0
- data/{example → tests/rails}/config/initializers/backtrace_silencers.rb +0 -0
- data/{example → tests/rails}/config/initializers/content_security_policy.rb +0 -0
- data/{example → tests/rails}/config/initializers/cookies_serializer.rb +0 -0
- data/{example → tests/rails}/config/initializers/filter_parameter_logging.rb +0 -0
- data/{example → tests/rails}/config/initializers/inflections.rb +0 -0
- data/{example → tests/rails}/config/initializers/mime_types.rb +0 -0
- data/{example → tests/rails}/config/initializers/tainted_love.rb +0 -0
- data/{example → tests/rails}/config/initializers/wrap_parameters.rb +0 -0
- data/{example → tests/rails}/config/locales/en.yml +0 -0
- data/{example → tests/rails}/config/puma.rb +0 -0
- data/{example → tests/rails}/config/routes.rb +6 -0
- data/{example → tests/rails}/config/spring.rb +0 -0
- data/{example → tests/rails}/config/storage.yml +0 -0
- data/{example → tests/rails}/db/migrate/20190311220346_create_products.rb +0 -0
- data/{example → tests/rails}/db/schema.rb +0 -0
- data/{example → tests/rails}/db/seeds.rb +0 -0
- data/{example/log → tests/rails/lib/assets}/.keep +0 -0
- data/{example/storage → tests/rails/lib/tasks}/.keep +0 -0
- data/{example/test/controllers → tests/rails/log}/.keep +0 -0
- data/{example → tests/rails}/package.json +0 -0
- data/{example → tests/rails}/public/404.html +0 -0
- data/{example → tests/rails}/public/422.html +0 -0
- data/{example → tests/rails}/public/500.html +0 -0
- data/{example → tests/rails}/public/apple-touch-icon-precomposed.png +0 -0
- data/{example → tests/rails}/public/apple-touch-icon.png +0 -0
- data/{example → tests/rails}/public/favicon.ico +0 -0
- data/{example → tests/rails}/public/robots.txt +0 -0
- data/{example/test/fixtures → tests/rails/storage}/.keep +0 -0
- data/tests/rails/test.sh +1 -0
- data/{example → tests/rails}/test/application_system_test_case.rb +0 -0
- data/{example/test/fixtures/files → tests/rails/test/controllers}/.keep +0 -0
- data/tests/rails/test/controllers/graphql_controller_test.rb +28 -0
- data/{example → tests/rails}/test/controllers/products_controller_test.rb +0 -0
- data/tests/rails/test/controllers/test_cases_controller_test.rb +54 -0
- data/{example/test/helpers → tests/rails/test/fixtures}/.keep +0 -0
- data/{example/test/integration → tests/rails/test/fixtures/files}/.keep +0 -0
- data/{example → tests/rails}/test/fixtures/products.yml +0 -0
- data/{example/test/mailers → tests/rails/test/helpers}/.keep +0 -0
- data/{example/test/models → tests/rails/test/integration}/.keep +0 -0
- data/{example/test/system → tests/rails/test/mailers}/.keep +0 -0
- data/{example/tmp → tests/rails/test/models}/.keep +0 -0
- data/{example → tests/rails}/test/models/product_test.rb +0 -0
- data/{example → tests/rails}/test/replacers/replace_active_record_test.rb +28 -0
- data/tests/rails/test/replacers/replace_rails_user_input_test.rb +13 -0
- data/{example → tests/rails}/test/replacers/replace_sprokets_test.rb +0 -0
- data/{example/vendor → tests/rails/test/system}/.keep +0 -0
- data/{example → tests/rails}/test/system/products_test.rb +0 -0
- data/{example → tests/rails}/test/test_helper.rb +0 -0
- data/tests/rails/tmp/.keep +0 -0
- data/tests/rails/vendor/.keep +0 -0
- data/tests/sinatra/Gemfile +3 -0
- data/tests/sinatra/Gemfile.lock +29 -0
- data/tests/sinatra/app.rb +26 -0
- data/tests/sinatra/test.sh +1 -0
- data/tests/sinatra/views/xss.erb +1 -0
- data/tools/web/Gemfile +1 -1
- data/tools/web/application.rb +17 -2
- data/tools/web/public/application.css +38 -2
- data/tools/web/views/index.erb +5 -11
- data/tools/web/views/input.erb +4 -0
- data/tools/web/views/line.erb +2 -2
- metadata +146 -111
- data/example/app/controllers/test_cases_controller.rb +0 -20
- data/example/test/controllers/test_cases_controller_test.rb +0 -39
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class GraphqlController < ApplicationController
|
2
|
+
def execute
|
3
|
+
variables = ensure_hash(params[:variables])
|
4
|
+
query = params[:query]
|
5
|
+
operation_name = params[:operationName]
|
6
|
+
context = {
|
7
|
+
# Query context goes here, for example:
|
8
|
+
# current_user: current_user,
|
9
|
+
}
|
10
|
+
result = ExampleSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
|
11
|
+
render json: result
|
12
|
+
rescue => e
|
13
|
+
raise e unless Rails.env.development?
|
14
|
+
handle_error_in_development e
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Handle form data, JSON body, or a blank value
|
20
|
+
def ensure_hash(ambiguous_param)
|
21
|
+
case ambiguous_param
|
22
|
+
when String
|
23
|
+
if ambiguous_param.present?
|
24
|
+
ensure_hash(JSON.parse(ambiguous_param))
|
25
|
+
else
|
26
|
+
{}
|
27
|
+
end
|
28
|
+
when Hash, ActionController::Parameters
|
29
|
+
ambiguous_param
|
30
|
+
when nil
|
31
|
+
{}
|
32
|
+
else
|
33
|
+
raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_error_in_development(e)
|
38
|
+
logger.error e.message
|
39
|
+
logger.error e.backtrace.join("\n")
|
40
|
+
|
41
|
+
render json: { error: { message: e.message, backtrace: e.backtrace }, data: {} }, status: 500
|
42
|
+
end
|
43
|
+
end
|
File without changes
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TestCasesController < ApplicationController
|
4
|
+
layout false
|
5
|
+
|
6
|
+
def xss
|
7
|
+
end
|
8
|
+
|
9
|
+
def unsafe_render
|
10
|
+
render(params[:file])
|
11
|
+
end
|
12
|
+
|
13
|
+
def render_inline
|
14
|
+
render(inline: params[:template])
|
15
|
+
end
|
16
|
+
|
17
|
+
def unsafe_redirect
|
18
|
+
redirect_to(params[:to])
|
19
|
+
end
|
20
|
+
|
21
|
+
def taint_test
|
22
|
+
cookies[:something] = 'asdf'
|
23
|
+
|
24
|
+
values = {
|
25
|
+
'route_parameter_value' => params[:route_param],
|
26
|
+
'get_parameter' => params[:get_param],
|
27
|
+
'get_array_parameter_0' => params[:get_array_param][0],
|
28
|
+
'get_array_parameter_1' => params[:get_array_param][1],
|
29
|
+
'parameter_name' => params.keys.first,
|
30
|
+
'header_value' => request.headers['Host'],
|
31
|
+
'header_name' => request.headers.to_h.keys.select { |k| k['HTTP_AAA'] }.first,
|
32
|
+
'cookie_value' => cookies[:something],
|
33
|
+
'cookie_name' => cookies.to_h.keys.first,
|
34
|
+
'fullpath' => request.original_fullpath
|
35
|
+
}
|
36
|
+
|
37
|
+
description = values.keys
|
38
|
+
tainted = values.values.map(&:tainted?)
|
39
|
+
sources = values.values.map(&:tainted_love_tags)
|
40
|
+
|
41
|
+
render json: description.zip(values.values, tainted, sources)
|
42
|
+
end
|
43
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Types
|
2
|
+
class QueryType < Types::BaseObject
|
3
|
+
field :object_argument_taint_test_case, Boolean, null: false do
|
4
|
+
argument :input, TaintTestCaseInput, required: true
|
5
|
+
end
|
6
|
+
|
7
|
+
field :string_argument_taint_test_case, Boolean, null: false do
|
8
|
+
argument :input, String, required: true
|
9
|
+
argument :input_default, String, required: false, default_value: "something"
|
10
|
+
end
|
11
|
+
|
12
|
+
field :mutate_context, Integer, null: true do
|
13
|
+
argument :id, Integer, required: true
|
14
|
+
end
|
15
|
+
|
16
|
+
field :whoami, Integer, null: true
|
17
|
+
|
18
|
+
field :products, [ProductType], null: true
|
19
|
+
|
20
|
+
def object_argument_taint_test_case(input:)
|
21
|
+
[
|
22
|
+
input.top_level_string.tainted?,
|
23
|
+
!input.default_value_untainted.tainted?
|
24
|
+
].all?
|
25
|
+
end
|
26
|
+
|
27
|
+
def string_argument_taint_test_case(input:, input_default:)
|
28
|
+
[
|
29
|
+
input.tainted?,
|
30
|
+
!input_default.tainted?
|
31
|
+
].all?
|
32
|
+
end
|
33
|
+
|
34
|
+
def mutate_context(id:)
|
35
|
+
context[:user_id] = id
|
36
|
+
end
|
37
|
+
|
38
|
+
def whoami
|
39
|
+
context[:user_id]
|
40
|
+
end
|
41
|
+
|
42
|
+
def products
|
43
|
+
Product.all
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,10 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Rails.application.routes.draw do
|
4
|
+
if Rails.env.development?
|
5
|
+
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
|
6
|
+
end
|
7
|
+
post "/graphql", to: "graphql#execute"
|
4
8
|
get 'test_cases/xss'
|
5
9
|
get 'test_cases/unsafe_render'
|
6
10
|
get 'test_cases/render_inline'
|
7
11
|
get 'test_cases/unsafe_redirect'
|
12
|
+
get 'test_cases/taint_test/:route_param' => 'test_cases#taint_test', as: 'test_cases_taint_test'
|
13
|
+
|
8
14
|
resources :products
|
9
15
|
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
|
10
16
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/tests/rails/test.sh
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
bundle exec rails test
|
File without changes
|
File without changes
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class GraphQLControllerTest < ActionDispatch::IntegrationTest
|
6
|
+
test "string arguments are tainted" do
|
7
|
+
response = run_graphql('{ stringArgumentTaintTestCase(input:"asdf") }')
|
8
|
+
|
9
|
+
assert_equal({ "data" => { "stringArgumentTaintTestCase" => true } }, response)
|
10
|
+
end
|
11
|
+
|
12
|
+
test "string in object arguments are tainted" do
|
13
|
+
response = run_graphql('{ objectArgumentTaintTestCase(input: { topLevelString: "Asdf" }) }')
|
14
|
+
|
15
|
+
assert_equal({ "data" => { "objectArgumentTaintTestCase" => true } }, response)
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_graphql(query)
|
19
|
+
params = {
|
20
|
+
query: query
|
21
|
+
}
|
22
|
+
|
23
|
+
post graphql_url, params: params
|
24
|
+
assert_response :success
|
25
|
+
|
26
|
+
response.parsed_body
|
27
|
+
end
|
28
|
+
end
|