summaryrefslogtreecommitdiff
path: root/doc/development/secure_coding_guidelines.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/secure_coding_guidelines.md')
-rw-r--r--doc/development/secure_coding_guidelines.md56
1 files changed, 55 insertions, 1 deletions
diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md
index e7dc24201aa..ebab0e59cc3 100644
--- a/doc/development/secure_coding_guidelines.md
+++ b/doc/development/secure_coding_guidelines.md
@@ -269,7 +269,7 @@ When user submitted data is included in responses to end users, which is just ab
### Mitigation
-In most situations, a two-step solution can be utilized: input validation and output encoding in the appropriate context.
+In most situations, a two-step solution can be used: input validation and output encoding in the appropriate context.
#### Input validation
@@ -505,3 +505,57 @@ out, _ = exec.Command("sh", "-c", "echo 1 | cat /etc/passwd").Output()
```
This outputs `1` followed by the content of `/etc/passwd`.
+
+## GitLab Internal Authorization
+
+### Introduction
+
+There are some cases where `users` passed in the code is actually referring to a `DeployToken`/`DeployKey` entity instead of a real `User`, because of the code below in **`/lib/api/api_guard.rb`**
+
+```ruby
+ def find_user_from_sources
+ strong_memoize(:find_user_from_sources) do
+ deploy_token_from_request ||
+ find_user_from_bearer_token ||
+ find_user_from_job_token ||
+ user_from_warden
+ end
+ end
+```
+
+### Past Vulnerable Code
+
+In some scenarios such as [this one](https://gitlab.com/gitlab-org/gitlab/-/issues/237795), user impersonation is possible because a `DeployToken` ID can be used in place of a `User` ID. This happened because there was no check on the line with `Gitlab::Auth::CurrentUserMode.bypass_session!(user.id)`. In this case, the `id` is actually a `DeployToken` ID instead of a `User` ID.
+
+```ruby
+ def find_current_user!
+ user = find_user_from_sources
+ return unless user
+
+ # Sessions are enforced to be unavailable for API calls, so ignore them for admin mode
+ Gitlab::Auth::CurrentUserMode.bypass_session!(user.id) if Feature.enabled?(:user_mode_in_session)
+
+ unless api_access_allowed?(user)
+ forbidden!(api_access_denied_message(user))
+ end
+```
+
+### Best Practices
+
+In order to prevent this from happening, it is recommended to use the method `user.is_a?(User)` to make sure it returns `true` when we are expecting to deal with a `User` object. This could prevent the ID confusion from the method `find_user_from_sources` mentioned above. Below code snippet shows the fixed code after applying the best practice to the vulnerable code above.
+
+```ruby
+ def find_current_user!
+ user = find_user_from_sources
+ return unless user
+
+ if user.is_a?(User) && Feature.enabled?(:user_mode_in_session)
+ # Sessions are enforced to be unavailable for API calls, so ignore them for admin mode
+ Gitlab::Auth::CurrentUserMode.bypass_session!(user.id)
+ end
+
+ unless api_access_allowed?(user)
+ forbidden!(api_access_denied_message(user))
+ end
+```
+ \ No newline at end of file