CVE-2023-43256 (JavaScript, published 2023-09-25T14:15Z)
Description: value: A path traversal in Gladys Assistant v4.26.1 and below allows authenticated attackers to extract sensitive files in the host machine by exploiting a non-sanitized user input.
Severity: nan (CVSS v3 base score: 6.5)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/GladysAssistant/Gladys
Files changed:
server/services/rtsp-camera/api/rtspCamera.controller.js
server/services/rtsp-camera/utils/validateStreamParams.js
server/test/services/rtsp-camera/controllers/rtspCamera.controller.test.js
Commit message: Camera Streaming: Fix validation of session_id and filename (#1847)



Vulnerable code:
const { Error404 } = require('../../../utils/httpErrors');
  it('should get streaming file', async () => {
        file: 'FILE_NOT_FOUND',

Fixed code:
const { Error404, Error400 } = require('../../../utils/httpErrors');
const { validateFilename, validateSessionId } = require('../utils/validateStreamParams');
      validateSessionId(req.params.folder);
      validateFilename(req.params.file);
      if (e instanceof Error400) {
        throw e;
      }
const { Error400 } = require('../../../utils/httpErrors');

const SESSION_ID_REGEX = /^camera-[a-zA-Z0-9-_]+$/;

// Session_id usually looks like "camera-7835d25d-b8ce-4824-a235-23637f778f83-39-50-13"
const validateSessionId = (sessionId) => {
  if (!SESSION_ID_REGEX.test(sessionId)) {
    throw new Error400('Invalid session id');
  }
};

const AUTHORIZED_FILENAMES = ['index.m3u8', 'index.m3u8.key', 'key_info_file.txt'];
const HLS_CHUNK_REGEX = /index[0-9]+.ts/;

const validateFilename = (filename) => {
  if (AUTHORIZED_FILENAMES.includes(filename)) {
    return;
  }

  if (!HLS_CHUNK_REGEX.test(filename)) {
    throw new Error400('Invalid filename');
  }
};

module.exports = {
  validateSessionId,
  validateFilename,
};
  it('should get index.m3u8 file', async () => {
  it('should get index1.ts file', async () => {
    const rtspCameraController = RtspCameraController(gladys, rtspCameraService);
    const req = {
      params: {
        folder: 'camera-1',
        file: 'index1.ts',
      },
    };
    await fse.ensureDir(path.join(gladys.config.tempFolder, 'camera-1'));
    await fse.writeFile(path.join(gladys.config.tempFolder, 'camera-1', 'index1.ts'), 'test-toto-content');
    const resWriteStream = fse.createWriteStream(path.join(gladys.config.tempFolder, 'camera-1', 'result.txt'));
    await rtspCameraController['get /api/v1/service/rtsp-camera/camera/streaming/:folder/:file'].controller(
      req,
      resWriteStream,
    );
  });
        file: 'index12212.ts',
  it('should return 400, bad request, invalid filename', async () => {
    const rtspCameraController = RtspCameraController(gladys, rtspCameraService);
    const req = {
      params: {
        folder: 'camera-1',
        file: 'lalalalala',
      },
    };
    const resWriteStream = {};
    const promise = rtspCameraController['get /api/v1/service/rtsp-camera/camera/streaming/:folder/:file'].controller(
      req,
      resWriteStream,
    );
    await chaiAssert.isRejected(promise, 'Invalid filename');
  });
  it('should return 400, bad request, invalid session id', async () => {
    const rtspCameraController = RtspCameraController(gladys, rtspCameraService);
    const req = {
      params: {
        folder: '.....',
        file: 'lalalalala',
      },
    };
    const resWriteStream = {};
    const promise = rtspCameraController['get /api/v1/service/rtsp-camera/camera/streaming/:folder/:file'].controller(
      req,
      resWriteStream,
    );
    await chaiAssert.isRejected(promise, 'Invalid session id');
  });