blob: 1123ff731368455a0e8d0d835bbbe6891e25480c (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
# frozen_string_literal: true
module Gitlab
module PathTraversal
extend self
PathTraversalAttackError = Class.new(StandardError)
private_class_method def logger
@logger ||= Gitlab::AppLogger
end
PATH_TRAVERSAL_REGEX = %r{(\A(\.{1,2})\z|\A\.\.[/\\]|[/\\]\.\.\z|[/\\]\.\.[/\\]|\n)}
# Ensure that the relative path will not traverse outside the base directory
# We url decode the path to avoid passing invalid paths forward in url encoded format.
# Also see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24223#note_284122580
# It also checks for ALT_SEPARATOR aka '\' (forward slash)
def check_path_traversal!(path)
return unless path
path = path.to_s if path.is_a?(Gitlab::HashedPath)
raise PathTraversalAttackError, 'Invalid path' unless path.is_a?(String)
path = ::Gitlab::Utils.decode_path(path)
if path.match?(PATH_TRAVERSAL_REGEX)
logger.warn(message: "Potential path traversal attempt detected", path: path.to_s)
raise PathTraversalAttackError, 'Invalid path'
end
path
end
def check_allowed_absolute_path!(path, allowlist)
return unless Pathname.new(path).absolute?
return if ::Gitlab::Utils.allowlisted?(path, allowlist)
raise StandardError, "path #{path} is not allowed"
end
def check_allowed_absolute_path_and_path_traversal!(path, path_allowlist)
traversal_path = check_path_traversal!(path)
raise StandardError, "path is not a string!" unless traversal_path.is_a?(String)
check_allowed_absolute_path!(traversal_path, path_allowlist)
end
end
end
|