CVE-2022-0726 (published 2022-02-23T14:15Z)

Missing Authorization in GitHub repository chocobozzz/peertube prior to 4.1.0.

Severity: MEDIUM
CVSS v2 base score: 5.5 (AV:N/AC:L/Au:S/C:P/I:P/A:N)
CVSS v3 base score: 5.4, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/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/chocobozzz/peertube
commit_details: repo_url: https://github.com/chocobozzz/peertube
author: Chocobozzz
author_date: 2022-02-22 14:16:34+01:00
msg: Check video privacy when creating comments/rates
repository: repo_url: https://github.com/chocobozzz/peertube
repo_name: Chocobozzz/PeerTube
description: ActivityPub-federated video streaming platform using P2P directly in your web browser
repo_language: TypeScript
owner: chocobozzz
file_changes: filename: video-comments.ts
change_type: ModificationType.MODIFY
diff: @@ -100,6 +100,14 @@ const addVideoCommentThreadValidator = [
 
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res)) return
+
+    if (!await checkCanSeeVideoIfPrivate(req, res, res.locals.videoAll)) {
+      return res.fail({
+        status: HttpStatusCode.FORBIDDEN_403,
+        message: 'Cannot access to this ressource'
+      })
+    }
+
     if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
     if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return
 
@@ -119,6 +127,14 @@ const addVideoCommentReplyValidator = [
 
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res)) return
+
+    if (!await checkCanSeeVideoIfPrivate(req, res, res.locals.videoAll)) {
+      return res.fail({
+        status: HttpStatusCode.FORBIDDEN_403,
+        message: 'Cannot access to this ressource'
+      })
+    }
+
     if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
     if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return
     if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, true)) return

programming_language: CoffeeScript
filename: video-rates.ts
change_type: ModificationType.MODIFY
diff: @@ -8,7 +8,7 @@ import { isRatingValid } from '../../../helpers/custom-validators/video-rates'
 import { isVideoRatingTypeValid } from '../../../helpers/custom-validators/videos'
 import { logger } from '../../../helpers/logger'
 import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
-import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
+import { areValidationErrors, checkCanSeeVideoIfPrivate, doesVideoExist, isValidVideoIdParam } from '../shared'
 
 const videoUpdateRateValidator = [
   isValidVideoIdParam('id'),
@@ -21,6 +21,13 @@ const videoUpdateRateValidator = [
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.id, res)) return
 
+    if (!await checkCanSeeVideoIfPrivate(req, res, res.locals.videoAll)) {
+      return res.fail({
+        status: HttpStatusCode.FORBIDDEN_403,
+        message: 'Cannot access to this ressource'
+      })
+    }
+
     return next()
   }
 ]

programming_language: CoffeeScript
filename: video-comments.ts
change_type: ModificationType.MODIFY
diff: @@ -19,10 +19,14 @@ const expect = chai.expect
 describe('Test video comments API validator', function () {
   let pathThread: string
   let pathComment: string
+
   let server: PeerTubeServer
+
   let video: VideoCreateResult
+
   let userAccessToken: string
   let userAccessToken2: string
+
   let commentId: number
   let privateCommentId: number
   let privateVideo: VideoCreateResult
@@ -203,9 +207,8 @@ describe('Test video comments API validator', function () {
 
     it('Should fail with an incorrect video', async function () {
       const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads'
-      const fields = {
-        text: 'super comment'
-      }
+      const fields = { text: 'super comment' }
+
       await makePostBodyRequest({
         url: server.url,
         path,
@@ -215,10 +218,21 @@ describe('Test video comments API validator', function () {
       })
     })
 
+    it('Should fail with a private video of another user', async function () {
+      const fields = { text: 'super comment' }
+
+      await makePostBodyRequest({
+        url: server.url,
+        path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
+        token: userAccessToken,
+        fields,
+        expectedStatus: HttpStatusCode.FORBIDDEN_403
+      })
+    })
+
     it('Should succeed with the correct parameters', async function () {
-      const fields = {
-        text: 'super comment'
-      }
+      const fields = { text: 'super comment' }
+
       await makePostBodyRequest({
         url: server.url,
         path: pathThread,
@@ -230,6 +244,7 @@ describe('Test video comments API validator', function () {
   })
 
   describe('When adding a comment to a thread', function () {
+
     it('Should fail with a non authenticated user', async function () {
       const fields = {
         text: 'text'
@@ -276,6 +291,18 @@ describe('Test video comments API validator', function () {
       })
     })
 
+    it('Should fail with a private video of another user', async function () {
+      const fields = { text: 'super comment' }
+
+      await makePostBodyRequest({
+        url: server.url,
+        path: '/api/v1/videos/' + privateVideo.uuid + '/comments/' + privateCommentId,
+        token: userAccessToken,
+        fields,
+        expectedStatus: HttpStatusCode.FORBIDDEN_403
+      })
+    })
+
     it('Should fail with an incorrect comment', async function () {
       const path = '/api/v1/videos/' + video.uuid + '/comments/124'
       const fields = {

programming_language: JavaScript
filename: videos.ts
change_type: ModificationType.MODIFY
diff: @@ -28,6 +28,7 @@ describe('Test videos API validator', function () {
   let channelId: number
   let channelName: string
   let video: VideoCreateResult
+  let privateVideo: VideoCreateResult
 
   // ---------------------------------------------------------------
 
@@ -49,6 +50,10 @@ describe('Test videos API validator', function () {
       channelName = body.videoChannels[0].name
       accountName = body.account.name + '@' + body.account.host
     }
+
+    {
+      privateVideo = await server.videos.quickUpload({ name: 'private video', privacy: VideoPrivacy.PRIVATE })
+    }
   })
 
   describe('When listing videos', function () {
@@ -783,6 +788,19 @@ describe('Test videos API validator', function () {
       await makePutBodyRequest({ url: server.url, path: path + videoId + '/rate', token: server.accessToken, fields })
     })
 
+    it('Should fail with a private video of another user', async function () {
+      const fields = {
+        rating: 'like'
+      }
+      await makePutBodyRequest({
+        url: server.url,
+        path: path + privateVideo.uuid + '/rate',
+        token: userAccessToken,
+        fields,
+        expectedStatus: HttpStatusCode.FORBIDDEN_403
+      })
+    })
+
     it('Should succeed with the correct parameters', async function () {
       const fields = {
         rating: 'like'

programming_language: JavaScript