Skip to content

Commit 3cda027

Browse files
committed
Update ignorelist for Brakeman after fixing working time queries
After careful consideration, we conclude that the same warnings present before are detected, just with a different hash and code path. Therefore, we simply update brakeman.ignore to account for these changes. According to the best of our knowledge and also considering the recent penetration test performed, there is no SQL injection present here that would require action. Relates to 590c834
1 parent 590c834 commit 3cda027

File tree

1 file changed

+7
-8
lines changed

1 file changed

+7
-8
lines changed

config/brakeman.ignore

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
{
2727
"warning_type": "SQL Injection",
2828
"warning_code": 0,
29-
"fingerprint": "1cd85bf7cb5861691738b889b473f9419d09e7924b9f8f5665b51de2b66ff64d",
29+
"fingerprint": "070a52e379818ec073deae3fb2e32266902f7862001941f1a5f0a73b258057a6",
3030
"check_name": "SQL",
3131
"message": "Possible SQL injection",
3232
"file": "app/models/exercise.rb",
33-
"line": 359,
33+
"line": 444,
3434
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
35-
"code": "self.class.connection.exec_query(\"\\n WITH working_time AS\\n (\\n SELECT contributor_id,\\n id,\\n exercise_id,\\n Max(score) AS max_score,\\n (created_at - Lag(created_at) OVER (partition BY contributor_id, exercise_id ORDER BY created_at)) AS working_time\\n FROM submissions\\n WHERE #{self.class.sanitize_sql([\"exercise_id = ?\", id])}\\n AND contributor_type IN ('ExternalUser', 'ProgrammingGroup')\\n GROUP BY contributor_id,\\n id,\\n exercise_id), max_points AS\\n (\\n SELECT context_id AS ex_id,\\n Sum(weight) AS max_points\\n FROM files\\n WHERE context_type = 'Exercise'\\n AND #{self.class.sanitize_sql([\"context_id = ?\", id])}\\n AND role IN ('teacher_defined_test', 'teacher_defined_linter')\\n GROUP BY context_id),\\n -- filter for rows containing max points\\n time_max_score AS\\n (\\n SELECT *\\n FROM working_time W1,\\n max_points MS\\n WHERE w1.exercise_id = ex_id\\n AND w1.max_score = ms.max_points),\\n -- find row containing the first time max points\\n first_time_max_score AS\\n (\\n SELECT id,\\n contributor_id,\\n exercise_id,\\n max_score,\\n working_time,\\n rn\\n FROM (\\n SELECT id,\\n contributor_id,\\n exercise_id,\\n max_score,\\n working_time,\\n Row_number() OVER(partition BY contributor_id, exercise_id ORDER BY id ASC) AS rn\\n FROM time_max_score) T\\n WHERE rn = 1), times_until_max_points AS\\n (\\n SELECT w.id,\\n w.contributor_id,\\n w.exercise_id,\\n w.max_score,\\n w.working_time,\\n m.id AS reachedmax_at\\n FROM working_time W,\\n first_time_max_score M\\n WHERE w.contributor_id = m.contributor_id\\n AND w.exercise_id = m.exercise_id\\n AND w.id <= m.id),\\n -- if user never makes it to max points, take all times\\n all_working_times_until_max AS (\\n (\\n SELECT id,\\n contributor_id,\\n exercise_id,\\n max_score,\\n working_time\\n FROM times_until_max_points)\\n UNION ALL\\n (\\n SELECT id,\\n contributor_id,\\n exercise_id,\\n max_score,\\n working_time\\n FROM working_time W1\\n WHERE NOT EXISTS\\n (\\n SELECT 1\\n FROM first_time_max_score F\\n WHERE f.contributor_id = w1.contributor_id\\n AND f.exercise_id = w1.exercise_id))), filtered_times_until_max AS\\n (\\n SELECT contributor_id,\\n exercise_id,\\n max_score,\\n CASE\\n WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0'\\n ELSE working_time\\n END AS working_time_new\\n FROM all_working_times_until_max ), result AS\\n (\\n SELECT e.external_id AS external_contributor_id,\\n f.contributor_id,\\n exercise_id,\\n Max(max_score) AS max_score,\\n Sum(working_time_new) AS working_time\\n FROM filtered_times_until_max f,\\n external_users e\\n WHERE f.contributor_id = e.id\\n GROUP BY e.external_id,\\n f.contributor_id,\\n exercise_id )\\n SELECT unnest(percentile_cont(#{self.class.sanitize_sql([\"array[?]\", quantiles])}) within GROUP (ORDER BY working_time))\\n FROM result\\n \")",
35+
"code": "self.class.connection.exec_query(\"\\n WITH working_time AS\\n (\\n SELECT contributor_id,\\n contributor_type,\\n created_at,\\n exercise_id,\\n Max(score) AS max_score,\\n (created_at - Lag(created_at) OVER (partition BY contributor_id, exercise_id ORDER BY created_at)) AS working_time\\n FROM submissions\\n WHERE #{self.class.sanitize_sql([\"exercise_id = ?\", id])}\\n GROUP BY contributor_id,\\n contributor_type,\\n id,\\n exercise_id), max_points AS\\n (\\n SELECT context_id AS ex_id,\\n Sum(weight) AS max_points\\n FROM files\\n WHERE context_type = 'Exercise'\\n AND #{self.class.sanitize_sql([\"context_id = ?\", id])}\\n AND role IN ('teacher_defined_test', 'teacher_defined_linter')\\n GROUP BY context_id),\\n -- filter for rows containing max points\\n time_max_score AS\\n (\\n SELECT *\\n FROM working_time W1,\\n max_points MS\\n WHERE w1.exercise_id = ex_id\\n AND w1.max_score = ms.max_points),\\n -- find row containing the first time max points\\n first_time_max_score AS\\n (\\n SELECT created_at,\\n contributor_id,\\n contributor_type,\\n exercise_id,\\n max_score,\\n working_time,\\n rn\\n FROM (\\n SELECT created_at,\\n contributor_id,\\n contributor_type,\\n exercise_id,\\n max_score,\\n working_time,\\n Row_number() OVER(partition BY contributor_id, contributor_type, exercise_id ORDER BY created_at ASC) AS rn\\n FROM time_max_score) T\\n WHERE rn = 1), times_until_max_points AS\\n (\\n SELECT w.created_at,\\n w.contributor_id,\\n w.contributor_type,\\n w.exercise_id,\\n w.max_score,\\n w.working_time,\\n m.created_at AS reachedmax_at\\n FROM working_time W,\\n first_time_max_score M\\n WHERE w.contributor_id = m.contributor_id\\n AND w.contributor_type = m.contributor_type\\n AND w.exercise_id = m.exercise_id\\n AND w.created_at <= m.created_at),\\n -- if user never makes it to max points, take all times\\n all_working_times_until_max AS (\\n (\\n SELECT created_at,\\n contributor_id,\\n contributor_type,\\n exercise_id,\\n max_score,\\n working_time\\n FROM times_until_max_points)\\n UNION ALL\\n (\\n SELECT created_at,\\n contributor_id,\\n contributor_type,\\n exercise_id,\\n max_score,\\n working_time\\n FROM working_time W1\\n WHERE NOT EXISTS\\n (\\n SELECT 1\\n FROM first_time_max_score F\\n WHERE f.contributor_id = w1.contributor_id\\n AND f.contributor_type = w1.contributor_type\\n AND f.exercise_id = w1.exercise_id))), filtered_times_until_max AS\\n (\\n SELECT contributor_id,\\n contributor_type,\\n exercise_id,\\n max_score,\\n CASE\\n WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0'\\n ELSE working_time\\n END AS working_time_new\\n FROM all_working_times_until_max ), result AS\\n (\\n SELECT contributor_id,\\n contributor_type,\\n exercise_id,\\n Max(max_score) AS max_score,\\n Sum(working_time_new) AS working_time\\n FROM filtered_times_until_max\\n GROUP BY contributor_id,\\n contributor_type,\\n exercise_id )\\n SELECT unnest(percentile_cont(#{self.class.sanitize_sql([\"array[?]\", quantiles])}) within GROUP (ORDER BY working_time))\\n FROM result\\n \")",
3636
"render_path": null,
3737
"location": {
3838
"type": "method",
@@ -49,13 +49,13 @@
4949
{
5050
"warning_type": "SQL Injection",
5151
"warning_code": 0,
52-
"fingerprint": "277bcd4729b671541c9cd43b3de3423f2f621578a55ecbf547ac2f42ec50e9eb",
52+
"fingerprint": "d78908a8173535fb77f61486223bd1f5b5353b5f01a32b5ab253883997102085",
5353
"check_name": "SQL",
5454
"message": "Possible SQL injection",
5555
"file": "app/models/exercise.rb",
56-
"line": 453,
56+
"line": 537,
5757
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
58-
"code": "self.class.connection.exec_query(\"\\n WITH WORKING_TIME AS\\n (SELECT contributor_id,\\n id,\\n exercise_id,\\n max(score) AS max_score,\\n (created_at - lag(created_at) OVER (PARTITION BY contributor_id, exercise_id\\n ORDER BY created_at)) AS working_time\\n FROM submissions\\n WHERE #{self.class.sanitize_sql([\"exercise_id = :id AND contributor_id = :contributor_id AND contributor_type = :contributor_type\", { :id => id, :contributor_id => contributor.id, :contributor_type => contributor.class.name }])}\\n GROUP BY contributor_id, id, exercise_id),\\n MAX_POINTS AS\\n (SELECT context_id AS ex_id, sum(weight) AS max_points FROM files WHERE context_type = 'Exercise' AND context_id = #{id} AND role IN ('teacher_defined_test', 'teacher_defined_linter') GROUP BY context_id),\\n\\n -- filter for rows containing max points\\n TIME_MAX_SCORE AS\\n (SELECT *\\n FROM WORKING_TIME W1, MAX_POINTS MS\\n WHERE W1.exercise_id = ex_id AND W1.max_score = MS.max_points),\\n\\n -- find row containing the first time max points\\n FIRST_TIME_MAX_SCORE AS\\n ( SELECT id,contributor_id,exercise_id,max_score,working_time, rn\\n FROM (\\n SELECT id,contributor_id,exercise_id,max_score,working_time,\\n ROW_NUMBER() OVER(PARTITION BY contributor_id, exercise_id ORDER BY id ASC) AS rn\\n FROM TIME_MAX_SCORE) T\\n WHERE rn = 1),\\n\\n TIMES_UNTIL_MAX_POINTS AS (\\n SELECT W.id, W.contributor_id, W.exercise_id, W.max_score, W.working_time, M.id AS reachedmax_at\\n FROM WORKING_TIME W, FIRST_TIME_MAX_SCORE M\\n WHERE W.contributor_id = M.contributor_id AND W.exercise_id = M.exercise_id AND W.id <= M.id),\\n\\n -- if contributor never makes it to max points, take all times\\n ALL_WORKING_TIMES_UNTIL_MAX AS\\n ((SELECT id, contributor_id, exercise_id, max_score, working_time FROM TIMES_UNTIL_MAX_POINTS)\\n UNION ALL\\n (SELECT id, contributor_id, exercise_id, max_score, working_time FROM WORKING_TIME W1\\n WHERE NOT EXISTS (SELECT 1 FROM FIRST_TIME_MAX_SCORE F WHERE F.contributor_id = W1.contributor_id AND F.exercise_id = W1.exercise_id))),\\n\\n FILTERED_TIMES_UNTIL_MAX AS\\n (\\n SELECT contributor_id,exercise_id, max_score, CASE WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0' ELSE working_time END AS working_time_new\\n FROM ALL_WORKING_TIMES_UNTIL_MAX\\n )\\n SELECT e.external_id AS external_contributor_id, f.contributor_id, exercise_id, MAX(max_score) AS max_score, sum(working_time_new) AS working_time\\n FROM FILTERED_TIMES_UNTIL_MAX f, EXTERNAL_USERS e\\n WHERE f.contributor_id = e.id GROUP BY e.external_id, f.contributor_id, exercise_id\\n \")",
58+
"code": "self.class.connection.exec_query(\"\\n WITH WORKING_TIME AS\\n (SELECT contributor_id,\\n contributor_type,\\n created_at,\\n exercise_id,\\n max(score) AS max_score,\\n (created_at - lag(created_at) OVER (PARTITION BY contributor_id, contributor_type, exercise_id\\n ORDER BY created_at)) AS working_time\\n FROM submissions\\n WHERE #{self.class.sanitize_sql([\"exercise_id = :id AND contributor_id = :contributor_id AND contributor_type = :contributor_type\", { :id => id, :contributor_id => contributor.id, :contributor_type => contributor.class.name }])}\\n GROUP BY contributor_id, contributor_type, created_at, exercise_id),\\n MAX_POINTS AS\\n (SELECT context_id AS ex_id, sum(weight) AS max_points FROM files WHERE context_type = 'Exercise' AND context_id = #{id} AND role IN ('teacher_defined_test', 'teacher_defined_linter') GROUP BY context_id),\\n\\n -- filter for rows containing max points\\n TIME_MAX_SCORE AS\\n (SELECT *\\n FROM WORKING_TIME W1, MAX_POINTS MS\\n WHERE W1.exercise_id = ex_id AND W1.max_score = MS.max_points),\\n\\n -- find row containing the first time max points\\n FIRST_TIME_MAX_SCORE AS\\n ( SELECT created_at, contributor_id, contributor_type, exercise_id, max_score, working_time, rn\\n FROM (\\n SELECT created_at, contributor_id, contributor_type, exercise_id, max_score, working_time,\\n ROW_NUMBER() OVER(PARTITION BY contributor_id, contributor_type, exercise_id ORDER BY created_at ASC) AS rn\\n FROM TIME_MAX_SCORE) T\\n WHERE rn = 1),\\n\\n TIMES_UNTIL_MAX_POINTS AS (\\n SELECT W.created_at, W.contributor_id, W.contributor_type, W.exercise_id, W.max_score, W.working_time, M.created_at AS reachedmax_at\\n FROM WORKING_TIME W, FIRST_TIME_MAX_SCORE M\\n WHERE W.contributor_id = M.contributor_id AND W.contributor_type = M.contributor_type AND W.exercise_id = M.exercise_id AND W.created_at <= M.created_at),\\n\\n -- if contributor never makes it to max points, take all times\\n ALL_WORKING_TIMES_UNTIL_MAX AS\\n ((SELECT created_at, contributor_id, contributor_type, exercise_id, max_score, working_time FROM TIMES_UNTIL_MAX_POINTS)\\n UNION ALL\\n (SELECT created_at, contributor_id, contributor_type, exercise_id, max_score, working_time FROM WORKING_TIME W1\\n WHERE NOT EXISTS (SELECT 1 FROM FIRST_TIME_MAX_SCORE F WHERE F.contributor_id = W1.contributor_id AND F.contributor_type = W1.contributor_type AND F.exercise_id = W1.exercise_id))),\\n\\n FILTERED_TIMES_UNTIL_MAX AS\\n (\\n SELECT contributor_id, contributor_type, exercise_id, max_score, CASE WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0' ELSE working_time END AS working_time_new\\n FROM ALL_WORKING_TIMES_UNTIL_MAX\\n )\\n SELECT contributor_id, contributor_type, exercise_id, MAX(max_score) AS max_score, sum(working_time_new) AS working_time\\n FROM FILTERED_TIMES_UNTIL_MAX\\n GROUP BY contributor_id, contributor_type, exercise_id\\n \")",
5959
"render_path": null,
6060
"location": {
6161
"type": "method",
@@ -70,6 +70,5 @@
7070
"note": "The `StatisticsHelper.working_time_larger_delta` already returns an SQL-escaped string and does not allow passing any params."
7171
}
7272
],
73-
"updated": "2024-08-22 23:05:04 +0200",
74-
"brakeman_version": "6.2.1"
73+
"brakeman_version": "7.1.0"
7574
}

0 commit comments

Comments
 (0)