CVE-2021-21246 (published 2021-01-15T21:15Z)

OneDev is an all-in-one devops platform. In OneDev before version 4.0.3, the REST UserResource endpoint performs a security check to make sure that only administrators can list user details. However for the `/users/{id}` endpoint there are no security checks enforced so it is possible to retrieve arbitrary user details including their Access Tokens! These access tokens can be used to access the API or clone code in the build spec via the HTTP(S) protocol. It has permissions to all projects accessible by the user account. This issue may lead to `Sensitive data leak` and leak the Access Token which can be used to impersonate the administrator or any other users. This issue was addressed in 4.0.3 by removing user info from restful api.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:P/I:N/A:N)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-862
cwe_name: Missing Authorization
description: The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are not applied, users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         

Fix information:
repo_url: https://github.com/theonedev/onedev
commit_details: repo_url: https://github.com/theonedev/onedev
author: Robin Shen
author_date: 2020-11-20 10:23:30+08:00
msg: Fix the issue that user access token can be leaked via restful api
repository: repo_url: https://github.com/theonedev/onedev
repo_name: theonedev/onedev
description: Git Server with CI/CD, Kanban, and Packages. Seamless integration. Unparalleled experience.
repo_language: Java
owner: theonedev
file_changes: filename: User.java
change_type: ModificationType.MODIFY
diff: @@ -112,6 +112,7 @@ public class User extends AbstractEntity implements AuthenticationInfo {
 
 	private String fullName;
 	
+	@JsonView(DefaultView.class)
 	@Embedded
 	private SsoInfo ssoInfo = new SsoInfo();
 	
@@ -119,6 +120,7 @@ public class User extends AbstractEntity implements AuthenticationInfo {
 	private String email;
 	
 	@Column(unique=true, nullable=false)
+	@JsonView(DefaultView.class)
 	private String accessToken = RandomStringUtils.randomAlphanumeric(ACCESS_TOKEN_LEN);
 	
 	@OneToMany(mappedBy="user", cascade=CascadeType.REMOVE)

programming_language: Java
filename: UserResource.java
change_type: ModificationType.DELETE
diff: @@ -1,71 +0,0 @@
-package io.onedev.server.rest;
-
-import java.util.Collection;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.shiro.authz.UnauthorizedException;
-import org.hibernate.criterion.Restrictions;
-import org.hibernate.validator.constraints.Email;
-
-import io.onedev.server.entitymanager.UserManager;
-import io.onedev.server.model.User;
-import io.onedev.server.persistence.dao.EntityCriteria;
-import io.onedev.server.rest.jersey.ValidQueryParams;
-import io.onedev.server.security.SecurityUtils;
-
-@Path("/users")
-@Consumes(MediaType.WILDCARD)
-@Produces(MediaType.APPLICATION_JSON)
-@Singleton
-public class UserResource {
-
-	private final UserManager userManager;
-	
-	@Inject
-	public UserResource(UserManager userManager) {
-		this.userManager = userManager;
-	}
-	
-	@ValidQueryParams
-	@GET
-	public Response query(@QueryParam("name") String name, @Email @QueryParam("email") String email, 
-			@QueryParam("offset") Integer offset, @QueryParam("count") Integer count, @Context UriInfo uriInfo) {
-    	if (!SecurityUtils.isAdministrator())
-    		throw new UnauthorizedException("Unauthorized access to user profiles");
-    	
-    	EntityCriteria<User> criteria = EntityCriteria.of(User.class);
-    	if (name != null)
-    		criteria.add(Restrictions.eq("name", name));
-		if (email != null)
-			criteria.add(Restrictions.eq("email", email));
-		
-    	if (offset == null)
-    		offset = 0;
-    	
-    	if (count == null || count > RestConstants.PAGE_SIZE) 
-    		count = RestConstants.PAGE_SIZE;
-
-    	Collection<User> users = userManager.query(criteria, offset, count);
-		
-		return Response.ok(users, RestConstants.JSON_UTF8).build();
-	}
-	
-    @GET
-    @Path("/{userId}")
-    public User get(@PathParam("userId") Long userId) {
-    	return userManager.load(userId);
-    }
-    
-}

programming_language: unknown