Module: Gitlab::PathTraversal

Extended by:
PathTraversal
Included in:
PathTraversal
Defined in:
lib/gitlab/path_traversal.rb

Constant Summary collapse

PathTraversalAttackError =
Class.new(StandardError)
PATH_TRAVERSAL_REGEX =
%r{\A(\.{1,2})\z|\A\.\.[/\\]|[/\\]\.\.\z|[/\\]\.\.[/\\]}
PATH_TRAVERSAL_REGEX_WITH_NEWLINE =
%r{(#{PATH_TRAVERSAL_REGEX}|\n)}

Instance Method Summary collapse

Instance Method Details

#check_allowed_absolute_path!(path, allowlist) ⇒ Object

Raises:

  • (StandardError)


47
48
49
50
51
52
# File 'lib/gitlab/path_traversal.rb', line 47

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

#check_allowed_absolute_path_and_path_traversal!(path, path_allowlist) ⇒ Object

Raises:

  • (StandardError)


54
55
56
57
58
59
# File 'lib/gitlab/path_traversal.rb', line 54

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

#check_path_traversal!(path) ⇒ Object

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 gitlab.com/gitlab-org/gitlab/-/merge_requests/24223#note_284122580 It also checks for backslash ‘\’, which is sometimes a File::ALT_SEPARATOR.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/gitlab/path_traversal.rb', line 19

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_traversal?(path)
    logger.warn(message: "Potential path traversal attempt detected", path: path.to_s)
    raise PathTraversalAttackError, 'Invalid path'
  end

  path
end

#path_traversal?(decoded_path, match_new_line: true) ⇒ Boolean

Returns:

  • (Boolean)


35
36
37
38
39
40
41
42
43
44
45
# File 'lib/gitlab/path_traversal.rb', line 35

def path_traversal?(decoded_path, match_new_line: true)
  return false unless decoded_path

  regex = if match_new_line
            PATH_TRAVERSAL_REGEX_WITH_NEWLINE
          else
            PATH_TRAVERSAL_REGEX
          end

  decoded_path.match?(regex)
end