CVE-2022-31142 (published 2022-07-14T19:15Z)

@fastify/bearer-auth is a Fastify plugin to require bearer Authorization headers. @fastify/bearer-auth prior to versions 7.0.2 and 8.0.1 does not securely use crypto.timingSafeEqual. A malicious attacker could estimate the length of one valid bearer token. According to the corresponding RFC 6750, the bearer token has only base64 valid characters, reducing the range of characters for a brute force attack. Version 7.0.2 and 8.0.1 of @fastify/bearer-auth contain a patch. There are currently no known workarounds. The package fastify-bearer-auth, which covers versions 6.0.3 and prior, is also vulnerable starting at version 5.0.1. Users of fastify-bearer-auth should upgrade to a patched version of @fastify/bearer-auth.

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-203
cwe_name: Observable Discrepancy
description: The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not.
extended_description: Discrepancies can take many forms, and variations may be detectable in timing, control flow, communications such as replies or requests, or general behavior. These discrepancies can reveal information about the product's operation or internal state to an unauthorized actor. In some cases, discrepancies can be used by attackers to form a side channel.
         

Fix information:
repo_url: https://github.com/fastify/fastify-bearer-auth
commit_details: repo_url: https://github.com/fastify/fastify-bearer-auth
author: Matteo Collina
author_date: 2022-07-13 11:28:55+02:00
msg: Merge pull request from GHSA-376v-xgjx-7mfr

* Correctly use crypto.timingSafeEqual

Signed-off-by: Matteo Collina <hello@matteocollina.com>
Co-Authored-By: Uzlopak <aras.abbasi@googlemail.com>

* apply requested change

Co-authored-by: Uzlopak <aras.abbasi@googlemail.com>
repository: repo_url: https://github.com/fastify/fastify-bearer-auth
repo_name: fastify/fastify-bearer-auth
description: A Fastify plugin to require bearer Authorization headers
repo_language: JavaScript
owner: fastify
file_changes: filename: plugin.js
change_type: ModificationType.MODIFY
diff: @@ -18,6 +18,13 @@ function verifyBearerAuthFactory (options) {
   if (_options.keys instanceof Set) _options.keys = Array.from(_options.keys)
   const { keys, errorResponse, contentType, bearerType, auth, addHook = true, verifyErrorLogLevel = 'error' } = _options
 
+  for (let i = 0, il = keys.length; i < il; ++i) {
+    if (typeof keys[i] !== 'string') {
+      throw new Error('options.keys has to contain only string entries')
+    }
+    keys[i] = Buffer.from(keys[i])
+  }
+
   return function verifyBearerAuth (request, reply, done) {
     const header = request.raw.headers.authorization
     if (!header) {
@@ -89,17 +96,19 @@ function verifyBearerAuthFactory (options) {
 }
 
 function authenticate (keys, key) {
-  return keys.findIndex((a) => compare(a, key)) !== -1
+  const b = Buffer.from(key)
+  return keys.findIndex((a) => compare(a, b)) !== -1
 }
 
 // perform constant-time comparison to prevent timing attacks
 function compare (a, b) {
-  try {
-    // may throw if they have different length, can't convert to Buffer, etc...
-    return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b))
-  } catch {
+  if (a.length !== b.length) {
+    // Delay return with cryptographically secure timing check.
+    crypto.timingSafeEqual(a, a)
     return false
   }
+
+  return crypto.timingSafeEqual(a, b)
 }
 
 function plugin (fastify, options, done) {

programming_language: JavaScript
filename: decorate.test.js
change_type: ModificationType.MODIFY
diff: @@ -20,3 +20,11 @@ test('verifyBearerAuthFactory', (t) => {
     t.ok(fastify.verifyBearerAuthFactory)
   })
 })
+
+test('verifyBearerAuthFactory', (t) => {
+  t.plan(1)
+  fastify.ready(() => {
+    const keys = { keys: new Set([123456]) }
+    t.throws(() => fastify.verifyBearerAuthFactory(keys), /keys has to contain only string entries/)
+  })
+})

programming_language: JavaScript
repo_url: https://github.com/fastify/fastify-bearer-auth
commit_details: repo_url: https://github.com/fastify/fastify-bearer-auth
author: Yuji Sugiura
author_date: 2020-05-28 23:01:22+09:00
msg: Use `crypto.timingSafeEqual()` instead of `secure-compare` module (#40)

* Use crypto.timingSafeEqual()

* Just try/catch Node core api
repository: repo_url: https://github.com/fastify/fastify-bearer-auth
repo_name: fastify/fastify-bearer-auth
description: A Fastify plugin to require bearer Authorization headers
repo_language: JavaScript
owner: fastify
file_changes: filename: package.json
change_type: ModificationType.MODIFY
diff: @@ -37,8 +37,7 @@
     "tsd": "^0.11.0"
   },
   "dependencies": {
-    "fastify-plugin": "^2.0.0",
-    "secure-compare": "^3.0.1"
+    "fastify-plugin": "^2.0.0"
   },
   "tsd": {
     "directory": "test",

programming_language: JavaScript
filename: plugin.js
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 'use strict'
 
+const crypto = require('crypto')
 const fp = require('fastify-plugin')
-const compare = require('secure-compare')
 
 function factory (options) {
   const defaultOptions = {
@@ -80,6 +80,16 @@ function authenticate (keys, key) {
   return keys.findIndex((a) => compare(a, key)) !== -1
 }
 
+// perform constant-time comparison to prevent timing attacks
+function compare (a, b) {
+  try {
+    // may throw if they have different length, can't convert to Buffer, etc...
+    return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b))
+  } catch {
+    return false
+  }
+}
+
 function plugin (fastify, options, next) {
   fastify.addHook('onRequest', factory(options))
   next()

programming_language: JavaScript