CVE-2021-43842 (JavaScript, published 2021-12-20T23:15Z)
Description: value: Wiki.js is a wiki app built on Node.js. Wiki.js versions 2.5.257 and earlier are vulnerable to stored cross-site scripting through a SVG file upload. By creating a crafted SVG file, a malicious Wiki.js user may stage a stored cross-site scripting attack. This allows the attacker to execute malicious JavaScript when the SVG is viewed directly by other users. Scripts do not execute when loaded inside a page via normal `<img>` tags. Commit 5d3e81496fba1f0fbd64eeb855f30f69a9040718 fixes this vulnerability by adding an optional (enabled by default) SVG sanitization step to all file uploads that match the SVG mime type. As a workaround, disable file upload for all non-trusted users. Wiki.js version 2.5.260 is the first production version to contain a patch. Version 2.5.258 is the first development build to contain a patch and is available only as a Docker image as requarks/wiki:canary-2.5.258.
Severity: LOW (CVSS v3 base score: 5.4)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/Requarks/wiki
Files changed:
client/components/admin/admin-security.vue
server/app/data.yml
server/graph/resolvers/site.js
server/graph/schemas/site.graphql
server/jobs/sanitize-svg.js
server/models/assets.js
Commit message: fix: sanitize SVG uploads


Vulnerable code:
        uploadMaxFiles: WIKI.config.uploads.maxFiles
          maxFiles: _.get(args, 'uploadMaxFiles', WIKI.config.uploads.maxFiles)
  host: String!
  title: String!
  description: String!
  robots: [String]!
  analyticsService: String!
  analyticsId: String!
  company: String!
  contentLicense: String!
  logoUrl: String!
  featurePageRatings: Boolean!
  featurePageComments: Boolean!
  featurePersonalWikis: Boolean!
  securityOpenRedirect: Boolean!
  securityIframe: Boolean!
  securityReferrerPolicy: Boolean!
  securityTrustProxy: Boolean!
  securitySRI: Boolean!
  securityHSTS: Boolean!
  securityHSTSDuration: Int!
  securityCSP: Boolean!
  securityCSPDirectives: String!
  uploadMaxFileSize: Int!
  uploadMaxFiles: Int!

Fixed code:
                  v-divider.mt-3
                  v-switch(
                    inset
                    label='Scan and Sanitize SVG Uploads'
                    color='primary'
                    v-model='config.uploadScanSVG'
                    persistent-hint
                    hint='Should SVG uploads be scanned for vulnerabilities and stripped of any potentially unsafe content.'
                    )
        uploadScanSVG: true,
              $uploadScanSVG: Boolean
                  uploadScanSVG: $uploadScanSVG
            uploadScanSVG: _.get(this.config, 'uploadScanSVG', false),
              uploadScanSVG
      scanSVG: true
        uploadMaxFiles: WIKI.config.uploads.maxFiles,
        uploadScanSVG: WIKI.config.uploads.scanSVG
          maxFiles: _.get(args, 'uploadMaxFiles', WIKI.config.uploads.maxFiles),
          scanSVG: _.get(args, 'uploadScanSVG', WIKI.config.uploads.scanSVG)
    uploadScanSVG: Boolean
  host: String
  title: String
  description: String
  robots: [String]
  analyticsService: String
  analyticsId: String
  company: String
  contentLicense: String
  logoUrl: String
  featurePageRatings: Boolean
  featurePageComments: Boolean
  featurePersonalWikis: Boolean
  securityOpenRedirect: Boolean
  securityIframe: Boolean
  securityReferrerPolicy: Boolean
  securityTrustProxy: Boolean
  securitySRI: Boolean
  securityHSTS: Boolean
  securityHSTSDuration: Int
  securityCSP: Boolean
  securityCSPDirectives: String
  uploadMaxFileSize: Int
  uploadMaxFiles: Int
  uploadScanSVG: Boolean
const fs = require('fs-extra')
const { JSDOM } = require('jsdom')
const createDOMPurify = require('dompurify')

/* global WIKI */

module.exports = async (svgPath) => {
  WIKI.logger.info(`Sanitizing SVG file upload...`)

  try {
    let svgContents = await fs.readFile(svgPath, 'utf8')

    const window = new JSDOM('').window
    const DOMPurify = createDOMPurify(window)

    svgContents = DOMPurify.sanitize(svgContents)

    await fs.writeFile(svgPath, svgContents)
    WIKI.logger.info(`Sanitized SVG file upload: [ COMPLETED ]`)
  } catch (err) {
    WIKI.logger.error(`Failed to sanitize SVG file upload: [ FAILED ]`)
    WIKI.logger.error(err.message)
    throw err
  }
}
    // Sanitize SVG contents
    if (WIKI.config.uploads.scanSVG && opts.mimetype === 'image/svg+xml') {
      const svgSanitizeJob = await WIKI.scheduler.registerJob({
        name: 'sanitize-svg',
        immediate: true,
        worker: true
      }, opts.path)
      await svgSanitizeJob.finished
    }