thuban 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/package.json +1 -1
- package/dist/packages/crucible/rules/code-scanner-core.json +11 -0
- package/dist/packages/scanner/ghost-code-detector.js +1 -1
- package/package.json +1 -1
- package/dist/packages/crucible/seeds/python/seed-021 2.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-022 2.py +0 -34
- package/dist/packages/crucible/seeds/python/seed-023 2.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-024 2.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-025 2.py +0 -40
- package/dist/packages/crucible/seeds/python/seed-026 2.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-027 2.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-028 2.py +0 -42
- package/dist/packages/crucible/seeds/python/seed-030 2.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-031 2.py +0 -34
- package/dist/packages/crucible/seeds/python/seed-036 2.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-037 2.py +0 -41
- package/dist/packages/crucible/seeds/python/seed-038 2.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-039 2.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-040 2.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-041 2.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-042 2.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-043 2.py +0 -32
- package/dist/packages/crucible/seeds/python/seed-044 2.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-045 2.py +0 -36
- package/dist/packages/crucible/seeds/python/seed-046 2.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-047 2.py +0 -44
- package/dist/packages/crucible/seeds/python/seed-048 2.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-049 2.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-050 2.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-051 2.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-052 2.py +0 -41
- package/dist/packages/crucible/seeds/ruby/seed-001 2.rb +0 -15
- package/dist/packages/crucible/seeds/ruby/seed-002 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-003 2.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-004 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-005 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-006 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-007 2.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-008 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-009 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-010 2.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-011 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-012 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-013 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-014 2.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-015 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-016 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-017 2.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-018 2.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-019 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-020 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-021 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-022 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-023 2.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-024 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-025 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-026 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-027 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-028 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-029 2.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-030 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-031 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-032 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-033 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-034 2.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-035 2.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-036 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-037 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-038 2.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-039 2.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-040 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-041 2.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-042 2.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-043 2.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-044 2.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-045 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-046 2.rb +0 -27
- package/dist/packages/crucible/seeds/ruby/seed-047 2.rb +0 -26
- package/dist/packages/crucible/seeds/ruby/seed-048 2.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-049 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-050 2.rb +0 -27
- package/dist/packages/crucible/seeds/rust/seed-001 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-002 2.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-003 2.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-004 2.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-005 2.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-006 2.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-007 2.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-008 2.rs +0 -19
- package/dist/packages/crucible/seeds/rust/seed-009 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-010 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-011 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-012 2.rs +0 -31
- package/dist/packages/crucible/seeds/rust/seed-013 2.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-014 2.rs +0 -30
- package/dist/packages/crucible/seeds/rust/seed-015 2.rs +0 -33
- package/dist/packages/crucible/seeds/rust/seed-016 2.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-017 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-018 2.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-019 2.rs +0 -36
- package/dist/packages/crucible/seeds/rust/seed-020 2.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-021 2.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-022 2.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-023 2.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-024 2.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-025 2.rs +0 -29
- package/dist/packages/crucible/seeds/rust/seed-026 2.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-027 2.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-028 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-029 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-030 2.rs +0 -30
- package/dist/packages/crucible/seeds/rust/seed-031 2.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-032 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-033 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-034 2.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-035 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-036 2.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-037 2.rs +0 -31
- package/dist/packages/crucible/seeds/rust/seed-038 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-039 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-040 2.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-041 2.rs +0 -32
- package/dist/packages/crucible/seeds/rust/seed-042 2.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-043 2.rs +0 -29
- package/dist/packages/crucible/seeds/rust/seed-044 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-045 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-046 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-047 2.rs +0 -34
- package/dist/packages/crucible/seeds/rust/seed-048 2.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-049 2.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-050 2.rs +0 -23
- package/dist/packages/crucible/seeds/ts/seed-001 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-002 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-003 2.ts +0 -28
- package/dist/packages/crucible/seeds/ts/seed-004 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-005 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-006 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-007 2.ts +0 -28
- package/dist/packages/crucible/seeds/ts/seed-008 2.ts +0 -40
- package/dist/packages/crucible/seeds/ts/seed-009 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-010 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-011 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-012 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-013 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-014 2.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-015 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-016 2.ts +0 -37
- package/dist/packages/crucible/seeds/ts/seed-017 2.ts +0 -44
- package/dist/packages/crucible/seeds/ts/seed-018 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-019 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-020 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-021 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-022 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-023 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-024 2.ts +0 -35
- package/dist/packages/crucible/seeds/ts/seed-025 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-026 2.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-027 2.ts +0 -30
- package/dist/packages/crucible/seeds/ts/seed-028 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-029 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-030 2.ts +0 -37
- package/dist/packages/crucible/seeds/ts/seed-031 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-032 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-033 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-034 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-035 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-036 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-037 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-038 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-039 2.ts +0 -35
- package/dist/packages/crucible/seeds/ts/seed-040 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-041 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-042 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-043 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-044 2.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-045 2.ts +0 -39
- package/dist/packages/crucible/seeds/ts/seed-046 2.ts +0 -41
- package/dist/packages/crucible/seeds/ts/seed-047 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-048 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-049 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-050 2.ts +0 -41
- package/dist/packages/crucible/seeds/ts/seed-051 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-052 2.ts +0 -36
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: sql_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: SQL injection via string interpolation in ActiveRecord where()
|
|
6
|
-
|
|
7
|
-
class UserController < ApplicationController
|
|
8
|
-
def search
|
|
9
|
-
username = params[:username]
|
|
10
|
-
@users = User.where("username = '#{username}'")
|
|
11
|
-
render json: @users
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def filter
|
|
15
|
-
role = params[:role]
|
|
16
|
-
since = params[:since]
|
|
17
|
-
@records = User.where("role = '#{role}' AND created_at >= '#{since}'")
|
|
18
|
-
render json: @records
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: sql_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: ActiveRecord find_by_sql with string interpolation
|
|
6
|
-
|
|
7
|
-
class ReportController < ApplicationController
|
|
8
|
-
def show
|
|
9
|
-
user_id = params[:user_id]
|
|
10
|
-
type = params[:type]
|
|
11
|
-
@data = Report.find_by_sql(
|
|
12
|
-
"SELECT * FROM reports WHERE user_id = #{user_id} AND type = '#{type}'"
|
|
13
|
-
)
|
|
14
|
-
render json: @data
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def custom_query
|
|
18
|
-
condition = params[:condition]
|
|
19
|
-
@results = ActiveRecord::Base.connection.execute(
|
|
20
|
-
"SELECT * FROM events WHERE #{condition}"
|
|
21
|
-
)
|
|
22
|
-
render json: @results.to_a
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: sql_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: ORDER BY clause built from user-supplied column name without whitelist
|
|
6
|
-
|
|
7
|
-
class ProductsController < ApplicationController
|
|
8
|
-
def index
|
|
9
|
-
sort_col = params[:sort_by]
|
|
10
|
-
sort_dir = params[:direction]
|
|
11
|
-
@products = Product.where("active = true").order("#{sort_col} #{sort_dir}")
|
|
12
|
-
render json: @products
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def search
|
|
16
|
-
term = params[:q]
|
|
17
|
-
category = params[:category]
|
|
18
|
-
@items = Product.where("name LIKE '%#{term}%' AND category = '#{category}'")
|
|
19
|
-
render json: @items
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: sql_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Raw SQL executed via connection.execute with user input
|
|
6
|
-
|
|
7
|
-
def run_analytics(dimension, filter_expr)
|
|
8
|
-
sql = "SELECT #{dimension}, COUNT(*) FROM events WHERE #{filter_expr} GROUP BY #{dimension}"
|
|
9
|
-
ActiveRecord::Base.connection.execute(sql)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def delete_records(table, condition)
|
|
13
|
-
ActiveRecord::Base.connection.execute(
|
|
14
|
-
"DELETE FROM #{table} WHERE #{condition}"
|
|
15
|
-
)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def update_field(table, field, value, id)
|
|
19
|
-
ActiveRecord::Base.connection.execute(
|
|
20
|
-
"UPDATE #{table} SET #{field} = '#{value}' WHERE id = #{id}"
|
|
21
|
-
)
|
|
22
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: sql_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Sequel dataset filter with string interpolation
|
|
6
|
-
|
|
7
|
-
require 'sequel'
|
|
8
|
-
|
|
9
|
-
DB = Sequel.connect('sqlite://db/production.sqlite3')
|
|
10
|
-
|
|
11
|
-
def find_user(username, password)
|
|
12
|
-
DB[:users].where("username = '#{username}' AND password = '#{password}'").first
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def get_orders(status, user_id)
|
|
16
|
-
DB[:orders].where("status = '#{status}' AND user_id = #{user_id}").all
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def search_items(keyword)
|
|
20
|
-
DB[:items].where("name LIKE '%#{keyword}%' OR description LIKE '%#{keyword}%'").all
|
|
21
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: sql_injection
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: ActiveRecord group/having clause with unparameterized user input
|
|
6
|
-
|
|
7
|
-
class AnalyticsController < ApplicationController
|
|
8
|
-
def aggregate
|
|
9
|
-
group_by = params[:group_by]
|
|
10
|
-
having = params[:having]
|
|
11
|
-
@data = Order.group(group_by)
|
|
12
|
-
.having("COUNT(*) #{having}")
|
|
13
|
-
.select("#{group_by}, COUNT(*) as total")
|
|
14
|
-
render json: @data
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: sql_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: pg gem exec_params replaced with exec — user string in raw SQL
|
|
6
|
-
|
|
7
|
-
require 'pg'
|
|
8
|
-
|
|
9
|
-
conn = PG.connect(dbname: 'production')
|
|
10
|
-
|
|
11
|
-
def login(conn, username, password)
|
|
12
|
-
result = conn.exec("SELECT * FROM users WHERE username = '#{username}' AND password_hash = '#{password}'")
|
|
13
|
-
result.first
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def get_profile(conn, user_id)
|
|
17
|
-
conn.exec("SELECT * FROM profiles WHERE user_id = #{user_id}").first
|
|
18
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: xss
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: render html: with user content — unescaped XSS
|
|
6
|
-
|
|
7
|
-
class CommentsController < ApplicationController
|
|
8
|
-
def show
|
|
9
|
-
@comment = Comment.find(params[:id])
|
|
10
|
-
render html: @comment.body.html_safe
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def preview
|
|
14
|
-
content = params[:content]
|
|
15
|
-
render html: content.html_safe
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: xss
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: raw() helper used with user-controlled content in ERB template
|
|
6
|
-
|
|
7
|
-
# In a Rails view (equivalent Ruby)
|
|
8
|
-
class ArticlesController < ApplicationController
|
|
9
|
-
helper_method :render_article
|
|
10
|
-
|
|
11
|
-
def show
|
|
12
|
-
@article = Article.find(params[:id])
|
|
13
|
-
@title = params[:title] || @article.title
|
|
14
|
-
@body = @article.body
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Equivalent ERB logic (Ruby):
|
|
19
|
-
def render_article_html(title, body, author_bio)
|
|
20
|
-
"<h1>#{raw(title)}</h1><div>#{raw(body)}</div><footer>#{raw(author_bio)}</footer>"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def raw(str)
|
|
24
|
-
str.to_s
|
|
25
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: xss
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Sinatra response body includes user param without escaping
|
|
6
|
-
|
|
7
|
-
require 'sinatra'
|
|
8
|
-
|
|
9
|
-
get '/greet' do
|
|
10
|
-
name = params[:name]
|
|
11
|
-
query = params[:q]
|
|
12
|
-
"<html><body><h1>Hello, #{name}!</h1><p>Results for: #{query}</p></body></html>"
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
get '/error' do
|
|
16
|
-
msg = params[:message]
|
|
17
|
-
"<div class='error'>#{msg}</div>"
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
post '/comment' do
|
|
21
|
-
comment = params[:comment]
|
|
22
|
-
"<p>Your comment: #{comment}</p>"
|
|
23
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: xss
|
|
3
|
-
# severity: medium
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: User content embedded in JSON output that is then eval()d client-side
|
|
6
|
-
|
|
7
|
-
class ApiController < ApplicationController
|
|
8
|
-
def user_data
|
|
9
|
-
user = User.find(params[:id])
|
|
10
|
-
bio = params[:bio] || user.bio
|
|
11
|
-
@json = { name: user.name, bio: bio, role: params[:role] }
|
|
12
|
-
render json: @json
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def config
|
|
16
|
-
callback = params[:callback]
|
|
17
|
-
data = { status: 'ok', user: current_user&.name }
|
|
18
|
-
render plain: "#{callback}(#{data.to_json})"
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: xss
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: content_tag or link_to with unescaped user attribute
|
|
6
|
-
|
|
7
|
-
def build_link(url, label, css_class)
|
|
8
|
-
"<a href='#{url}' class='#{css_class}'>#{label}</a>"
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def build_input(name, value, placeholder)
|
|
12
|
-
"<input name='#{name}' value='#{value}' placeholder='#{placeholder}'>"
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def build_script_tag(variable_name, data)
|
|
16
|
-
"<script>var #{variable_name} = #{data.to_json};</script>"
|
|
17
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: xss
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: ActionMailer HTML email built with unescaped user content
|
|
6
|
-
|
|
7
|
-
class NotificationMailer < ApplicationMailer
|
|
8
|
-
def welcome_email(user, custom_message)
|
|
9
|
-
@user = user
|
|
10
|
-
@message = custom_message
|
|
11
|
-
@subject = params[:subject] || "Welcome!"
|
|
12
|
-
|
|
13
|
-
mail(
|
|
14
|
-
to: @user.email,
|
|
15
|
-
subject: @subject
|
|
16
|
-
) do |format|
|
|
17
|
-
format.html { render html: "<h1>#{@user.name}</h1><p>#{@message}</p>".html_safe }
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: xss
|
|
3
|
-
# severity: medium
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: ERB template rendered with user string directly substituted
|
|
6
|
-
|
|
7
|
-
require 'erb'
|
|
8
|
-
|
|
9
|
-
def render_template(template_string, user_data)
|
|
10
|
-
ERB.new(template_string).result(binding)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def personalize_email(user_name, promo_code)
|
|
14
|
-
template = "Hello <%= user_name %>, your promo code is: <%= promo_code %>"
|
|
15
|
-
ERB.new(template).result(binding)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def build_page(title, body, footer)
|
|
19
|
-
tmpl = "<html><head><title><%= title %></title></head><body><%= body %><footer><%= footer %></footer></body></html>"
|
|
20
|
-
ERB.new(tmpl).result(binding)
|
|
21
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: command_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Backtick operator with user-supplied input — command injection
|
|
6
|
-
|
|
7
|
-
class SystemController < ApplicationController
|
|
8
|
-
def ping
|
|
9
|
-
host = params[:host]
|
|
10
|
-
result = `ping -c 4 #{host}`
|
|
11
|
-
render plain: result
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def dns_lookup
|
|
15
|
-
domain = params[:domain]
|
|
16
|
-
output = `nslookup #{domain}`
|
|
17
|
-
render plain: output
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: command_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: system() with user-controlled arguments — command injection
|
|
6
|
-
|
|
7
|
-
def convert_image(src, dest, width, height)
|
|
8
|
-
system("convert #{src} -resize #{width}x#{height} #{dest}")
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def compress_archive(dir_path, output_name)
|
|
12
|
-
system("tar -czf /tmp/#{output_name} #{dir_path}")
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def run_script(script_name, args)
|
|
16
|
-
system("/opt/scripts/#{script_name} #{args}")
|
|
17
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: command_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: exec() with user-controlled command — replaces process, no return
|
|
6
|
-
|
|
7
|
-
def execute_task(command)
|
|
8
|
-
exec(command)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def run_user_script(script_path, user_arg)
|
|
12
|
-
exec("ruby #{script_path} #{user_arg}")
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def start_service(service_name, config_file)
|
|
16
|
-
exec("#{service_name} --config #{config_file}")
|
|
17
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: command_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Open3.capture2 with shell string — user input in format string
|
|
6
|
-
|
|
7
|
-
require 'open3'
|
|
8
|
-
|
|
9
|
-
def run_ffmpeg(input_file, output_file, codec)
|
|
10
|
-
cmd = "ffmpeg -i '#{input_file}' -c:v #{codec} '#{output_file}'"
|
|
11
|
-
stdout, stderr, status = Open3.capture2(cmd)
|
|
12
|
-
{ output: stdout, error: stderr, success: status.success? }
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def grep_logs(pattern, log_file)
|
|
16
|
-
stdout, _ = Open3.capture2("grep -n '#{pattern}' /var/log/#{log_file}")
|
|
17
|
-
stdout
|
|
18
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: command_injection
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: IO.popen with user-controlled shell string
|
|
6
|
-
|
|
7
|
-
def tail_log(log_name, lines)
|
|
8
|
-
IO.popen("tail -n #{lines} /var/log/#{log_name}") do |f|
|
|
9
|
-
f.read
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def search_file(filename, keyword)
|
|
14
|
-
IO.popen("grep '#{keyword}' /data/#{filename}") do |io|
|
|
15
|
-
io.read
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def pipe_command(cmd)
|
|
20
|
-
IO.popen(cmd) { |f| f.read }
|
|
21
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: command_injection
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Kernel.system called with interpolated hostname for network diagnostics
|
|
6
|
-
|
|
7
|
-
class DiagnosticsController < ApplicationController
|
|
8
|
-
def check_connectivity
|
|
9
|
-
host = params[:host]
|
|
10
|
-
port = params[:port]
|
|
11
|
-
timeout = params[:timeout] || '5'
|
|
12
|
-
|
|
13
|
-
result = `nc -zv -w #{timeout} #{host} #{port} 2>&1`
|
|
14
|
-
render json: { output: result, host: host, port: port }
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def whois_lookup
|
|
18
|
-
domain = params[:domain]
|
|
19
|
-
output = `whois #{domain}`
|
|
20
|
-
render plain: output
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: path_traversal
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: File.read with unvalidated user-supplied path
|
|
6
|
-
|
|
7
|
-
class FilesController < ApplicationController
|
|
8
|
-
def show
|
|
9
|
-
filename = params[:filename]
|
|
10
|
-
content = File.read("/var/app/uploads/#{filename}")
|
|
11
|
-
render plain: content
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def download
|
|
15
|
-
path = params[:path]
|
|
16
|
-
data = File.read(path)
|
|
17
|
-
send_data data, filename: File.basename(path)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: path_traversal
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: send_file with user-controlled path — arbitrary file download
|
|
6
|
-
|
|
7
|
-
class DownloadsController < ApplicationController
|
|
8
|
-
def get_file
|
|
9
|
-
filename = params[:file]
|
|
10
|
-
base_dir = Rails.root.join('public', 'downloads')
|
|
11
|
-
file_path = File.join(base_dir, filename)
|
|
12
|
-
send_file file_path
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def export
|
|
16
|
-
name = params[:name]
|
|
17
|
-
path = "/var/reports/#{name}"
|
|
18
|
-
send_file path, type: 'application/octet-stream'
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: path_traversal
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Zip extraction writes files using entry name without sanitization — zip slip
|
|
6
|
-
|
|
7
|
-
require 'zip'
|
|
8
|
-
|
|
9
|
-
def extract_zip(zip_path, dest_dir)
|
|
10
|
-
Zip::File.open(zip_path) do |zip|
|
|
11
|
-
zip.each do |entry|
|
|
12
|
-
output_path = File.join(dest_dir, entry.name)
|
|
13
|
-
FileUtils.mkdir_p(File.dirname(output_path))
|
|
14
|
-
entry.extract(output_path) { true }
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: path_traversal
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: File.write to user-controlled destination path
|
|
6
|
-
|
|
7
|
-
def save_export(filename, data)
|
|
8
|
-
path = "/var/app/exports/#{filename}"
|
|
9
|
-
File.write(path, data)
|
|
10
|
-
path
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def cache_response(cache_key, content)
|
|
14
|
-
cache_path = "/tmp/cache/#{cache_key}"
|
|
15
|
-
FileUtils.mkdir_p(File.dirname(cache_path))
|
|
16
|
-
File.write(cache_path, content)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def write_template(template_name, subdir, content)
|
|
20
|
-
full_path = "/app/templates/#{subdir}/#{template_name}"
|
|
21
|
-
File.write(full_path, content)
|
|
22
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: path_traversal
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Dir.glob and File.open with user-controlled subdirectory
|
|
6
|
-
|
|
7
|
-
def list_files(base_dir, subdir)
|
|
8
|
-
Dir.glob("#{base_dir}/#{subdir}/*").map { |f| File.basename(f) }
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def read_config(config_name)
|
|
12
|
-
File.open("/etc/app/configs/#{config_name}") { |f| f.read }
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def load_plugin(plugin_id)
|
|
16
|
-
manifest = File.read("./plugins/#{plugin_id}/manifest.json")
|
|
17
|
-
JSON.parse(manifest)
|
|
18
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: mass_assignment
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: params.permit(:all) or ActionController::Parameters without strong params
|
|
6
|
-
|
|
7
|
-
class UsersController < ApplicationController
|
|
8
|
-
def update
|
|
9
|
-
@user = User.find(params[:id])
|
|
10
|
-
@user.update(params[:user])
|
|
11
|
-
redirect_to @user
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def create
|
|
15
|
-
@user = User.new(params[:user].permit!)
|
|
16
|
-
@user.save
|
|
17
|
-
render json: @user
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: mass_assignment
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: ActiveRecord.new(params) without strong parameters — mass assignment
|
|
6
|
-
|
|
7
|
-
class ProfilesController < ApplicationController
|
|
8
|
-
def update
|
|
9
|
-
profile = Profile.find(params[:id])
|
|
10
|
-
profile.update_attributes(params[:profile])
|
|
11
|
-
render json: profile
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def create
|
|
15
|
-
profile = Profile.new(params)
|
|
16
|
-
profile.save!
|
|
17
|
-
render json: profile, status: :created
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: mass_assignment
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: attr_accessible :all or missing attr_protected — mass assignment in model
|
|
6
|
-
|
|
7
|
-
class User < ActiveRecord::Base
|
|
8
|
-
# No attr_protected or attr_accessible defined
|
|
9
|
-
# Allows setting admin, role, confirmed fields via mass assignment
|
|
10
|
-
|
|
11
|
-
def self.create_from_params(params)
|
|
12
|
-
create(params)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.register(registration_params)
|
|
16
|
-
new(registration_params).tap(&:save)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: mass_assignment
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: slice(:all) or no-arg permit! allowing all user-supplied attributes
|
|
6
|
-
|
|
7
|
-
class OrdersController < ApplicationController
|
|
8
|
-
def create
|
|
9
|
-
permitted = params.require(:order).permit!
|
|
10
|
-
@order = Order.create(permitted)
|
|
11
|
-
render json: @order
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def bulk_update
|
|
15
|
-
params[:records].each do |record_params|
|
|
16
|
-
item = Item.find(record_params[:id])
|
|
17
|
-
item.update(record_params.except(:id))
|
|
18
|
-
end
|
|
19
|
-
render json: { updated: params[:records].count }
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: mass_assignment
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Mongoid or other ODM with unfiltered hash assignment
|
|
6
|
-
|
|
7
|
-
require 'mongoid'
|
|
8
|
-
|
|
9
|
-
class Document
|
|
10
|
-
include Mongoid::Document
|
|
11
|
-
|
|
12
|
-
field :title, type: String
|
|
13
|
-
field :content, type: String
|
|
14
|
-
field :admin, type: Boolean, default: false
|
|
15
|
-
field :role, type: String, default: 'user'
|
|
16
|
-
|
|
17
|
-
def self.create_from_hash(attrs)
|
|
18
|
-
create!(attrs)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def update_from_request(request_params)
|
|
22
|
-
update_attributes!(request_params)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: ssrf
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Net::HTTP.get_response with user-controlled URL — SSRF
|
|
6
|
-
|
|
7
|
-
require 'net/http'
|
|
8
|
-
require 'uri'
|
|
9
|
-
|
|
10
|
-
class ProxyController < ApplicationController
|
|
11
|
-
def fetch
|
|
12
|
-
url = params[:url]
|
|
13
|
-
uri = URI.parse(url)
|
|
14
|
-
response = Net::HTTP.get_response(uri)
|
|
15
|
-
render plain: response.body
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def check_endpoint
|
|
19
|
-
target = params[:endpoint]
|
|
20
|
-
uri = URI(target)
|
|
21
|
-
res = Net::HTTP.get_response(uri)
|
|
22
|
-
render json: { status: res.code, body: res.body[0..200] }
|
|
23
|
-
end
|
|
24
|
-
end
|