javascript.express.security.audit.express-libxml-vm-noent.express-libxml-vm-noent

profile photo of semgrepsemgrep
Author
unknown
Download Count*

Detected use of parseXml() function with the noent field set to true. This can lead to an XML External Entities (XXE) attack if untrusted data is passed into it.

Run Locally

Run in CI

Defintion

rules:
  - id: express-libxml-vm-noent
    message: Detected use of parseXml() function with the `noent` field set to
      `true`. This can lead to an XML External Entities (XXE) attack if
      untrusted data is passed into it.
    metadata:
      references:
        - https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
      owasp:
        - A04:2017 - XML External Entities (XXE)
        - A05:2021 - Security Misconfiguration
      cwe:
        - "CWE-611: Improper Restriction of XML External Entity Reference"
      category: security
      technology:
        - express
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: HIGH
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - XML Injection
    languages:
      - javascript
      - typescript
    severity: WARNING
    patterns:
      - pattern-either:
          - patterns:
              - pattern-either:
                  - pattern: $VM.runInContext("$CMD", ...)
                  - pattern: $VM.runInNewContext("$CMD", ...)
                  - pattern: $VM.runInThisContext("$CMD", ...)
                  - pattern: $VM.compileFunction("$CMD", ...)
              - metavariable-pattern:
                  metavariable: $CMD
                  language: typescript
                  pattern-either:
                    - pattern: |
                        $LIBXML.parseXml($DATA, {..., noent: true, ...}, ...)
                    - patterns:
                        - pattern-inside: |
                            $OPTS = {..., noent: true, ...}
                            ...
                        - pattern: $LIBXML.parseXml( $DATA, $OPTS )
          - pattern: |
              $LIBXML.parseXml($DATA, {..., noent: true, ...}, ...)
          - patterns:
              - pattern-inside: |
                  $OPTS = {..., noent: true, ...}
                  ...
              - pattern: $LIBXML.parseXml( $DATA, $OPTS )

Examples

express-libxml-vm-noent.js

function handleXmlUpload ({ file }: Request, res: Response, next: NextFunction) {
  if (utils.endsWith(file?.originalname.toLowerCase(), '.xml')) {
    if (file?.buffer && !utils.disableOnContainerEnv()) { // XXE attacks in Docker/Heroku containers regularly cause "segfault" crashes
      const data = file.buffer.toString()
      try {
        const sandbox = { libxml, data }
        vm.createContext(sandbox)
        
        // ruleid: express-libxml-vm-noent
        const xmlDoc = vm.runInContext('libxml.parseXml(data, { noblanks: true, noent: true, nocdata: true })', sandbox, { timeout: 2000 })

        // ruleid: express-libxml-vm-noent
        const xmlDoc = vm.runInContext("libxml.parseXml(data, { noblanks: true, noent: true, nocdata: true })", sandbox, { timeout: 2000 })

        // ruleid: express-libxml-vm-noent
        libxml.parseXml(data, { noblanks: true, noent: true, nocdata: true })

        const xml_opts = { noblanks: true, noent: true, nocdata: true }
        // ruleid: express-libxml-vm-noent
        libxml.parseXml(data, xml_opts)

        // ok: express-libxml-vm-noent
        libxml.parseXml(data, { noblanks: true, nocdata: true })

        const xmlString = xmlDoc.toString(false)
        res.status(410)
        next(new Error('B2B customer complaints via file upload have been deprecated for security reasons: ' + utils.trunc(xmlString, 400) + ' (' + file.originalname + ')'))
      } catch (err) {
        if (utils.contains(err.message, 'Script execution timed out')) {
          res.status(503)
          next(new Error('Sorry, we are temporarily not available! Please try again later.'))
        } else {
          res.status(410)
          next(new Error('B2B customer complaints via file upload have been deprecated for security reasons: ' + err.message + ' (' + file.originalname + ')'))
        }
      }
    } else {
      res.status(410)
      next(new Error('B2B customer complaints via file upload have been deprecated for security reasons (' + file?.originalname + ')'))
    }
  }
  res.status(204).end()
}