CVE-2022-0170 (TypeScript, published 2022-01-11T16:15Z)
Description: value: peertube is vulnerable to Improper Access Control
Severity: MEDIUM (CVSS v3 base score: 4.3)
Weakness: CWE-284 \u2014 Improper Access Control
The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.
Repository: https://github.com/chocobozzz/peertube
Files changed:
server/middlewares/validators/videos/video-comments.ts
server/tests/api/check-params/video-comments.ts
Commit message: Don't display comments of private/internal videos


Vulnerable code:
import { areValidationErrors, doesVideoCommentExist, doesVideoCommentThreadExist, doesVideoExist, isValidVideoIdParam } from '../shared'
import { HttpStatusCode, VideoCreateResult } from '@shared/models'

Fixed code:
import {
  areValidationErrors,
  checkCanSeeVideoIfPrivate,
  doesVideoCommentExist,
  doesVideoCommentThreadExist,
  doesVideoExist,
  isValidVideoIdParam
} from '../shared'
    if (!await checkCanSeeVideoIfPrivate(req, res, res.locals.onlyVideo)) {
      return res.fail({
        status: HttpStatusCode.FORBIDDEN_403,
        message: 'Cannot list comments of private/internal/blocklisted video'
      })
    }

    if (!await checkCanSeeVideoIfPrivate(req, res, res.locals.onlyVideo)) {
      return res.fail({
        status: HttpStatusCode.FORBIDDEN_403,
        message: 'Cannot list threads of private/internal/blocklisted video'
      })
    }

import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models'
  let privateCommentId: number
  let privateVideo: VideoCreateResult
    {
      privateVideo = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PRIVATE } })
    }

    {
      const created = await server.comments.createThread({ videoId: privateVideo.uuid, text: 'coucou' })
      privateCommentId = created.id
    }


    it('Should fail with a private video without token', async function () {
      await makeGetRequest({
        url: server.url,
        path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
        expectedStatus: HttpStatusCode.UNAUTHORIZED_401
      })
    })

    it('Should fail with another user token', async function () {
      await makeGetRequest({
        url: server.url,
        token: userAccessToken,
        path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
        expectedStatus: HttpStatusCode.FORBIDDEN_403
      })
    })

    it('Should succeed with the correct params', async function () {
      await makeGetRequest({
        url: server.url,
        token: server.accessToken,
        path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
        expectedStatus: HttpStatusCode.OK_200
      })
    })
    it('Should fail with a private video without token', async function () {
      await makeGetRequest({
        url: server.url,
        path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
        expectedStatus: HttpStatusCode.UNAUTHORIZED_401
      })
    })

    it('Should fail with another user token', async function () {
      await makeGetRequest({
        url: server.url,
        token: userAccessToken,
        path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
        expectedStatus: HttpStatusCode.FORBIDDEN_403
      })
    })

      await makeGetRequest({
        url: server.url,
        token: server.accessToken,
        path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
        expectedStatus: HttpStatusCode.OK_200
      })