VYPR
Moderate severityNVD Advisory· Published Apr 19, 2023· Updated Nov 7, 2025

CVE-2023-22893

CVE-2023-22893

Description

Strapi through 4.5.5 does not verify the access or ID tokens issued during the OAuth flow when the AWS Cognito login provider is used for authentication. A remote attacker could forge an ID token that is signed using the 'None' type algorithm to bypass authentication and impersonate any user that use AWS Cognito for authentication.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Strapi before 4.5.6 fails to validate AWS Cognito ID tokens, enabling attackers to forge tokens with 'None' algorithm and impersonate any user.

Vulnerability

Details

CVE-2023-22893 is an authentication bypass in Strapi (through version 4.5.5) that specifically affects installations using the AWS Cognito login provider. The root cause is the lack of verification of the access or ID tokens issued during the OAuth flow. Strapi accepts tokens signed with the 'None' algorithm, allowing an attacker to forge a valid-looking ID token without a proper signature [1][4].

Exploitation

An unauthenticated remote attacker can craft a malicious JWT using the 'None' algorithm and submit it to Strapi's login endpoint. The server does not validate the token's signature or algorithm, so it accepts the forged token and authenticates the attacker as the user specified in the token claims. No prior access or special privileges are required. The attack only applies when Strapi is configured with the AWS Cognito provider [2].

Impact

Successful exploitation allows the attacker to impersonate any user that uses AWS Cognito for authentication. If the impersonated user has administrative privileges, the attacker gains full control over the Strapi instance, including the ability to modify content, access sensitive data, and potentially execute further attacks (as demonstrated by chaining with other vulnerabilities like CVE-2023-22621) [1].

Mitigation

Strapi patched this vulnerability in version 4.5.6. Users are strongly advised to upgrade immediately. Strapi version 3.x.x has reached end-of-life and will not receive security updates, so users on v3 must migrate to a patched v4.x version. No workarounds are available beyond upgrading [2][4].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@strapi/plugin-users-permissionsnpm
>= 3.2.1, < 4.6.04.6.0

Affected products

2

Patches

3
8bbbd7383a20

Split the url to fill origin and path values in purest

https://github.com/strapi/strapiChristian CapeansJan 25, 2023via ghsa
1 file changed · +3 3
  • packages/plugins/users-permissions/server/services/providers-registry.js+3 3 modified
    @@ -17,8 +17,8 @@ const getCognitoPayload = async ({ idToken, jwksUrl, purest }) => {
       const config = {
         cognito: {
           discovery: {
    -        origin: jwksUrl,
    -        path: '',
    +        origin: jwksUrl.origin,
    +        path: jwksUrl.pathname,
           },
         },
       };
    @@ -62,7 +62,7 @@ const getInitialProviders = ({ purest }) => ({
           });
       },
       async cognito({ query, providers }) {
    -    const jwksUrl = providers.cognito.jwksurl;
    +    const jwksUrl = new URL(providers.cognito.jwksurl);
         const idToken = query.id_token;
         const tokenPayload = await getCognitoPayload({ idToken, jwksUrl, purest });
         return {
    
eeab43b57707

Store jwk set url in strapi core

https://github.com/strapi/strapiChristian CapeansJan 11, 2023via ghsa
2 files changed · +20 6
  • packages/plugins/users-permissions/admin/src/pages/Providers/utils/forms.js+15 0 modified
    @@ -173,6 +173,21 @@ const forms = {
               },
             },
           ],
    +      [
    +        {
    +          intlLabel: {
    +            id: getTrad({ id: 'PopUpForm.Providers.jwksurl.label' }),
    +            defaultMessage: 'JWKS URL',
    +          },
    +          name: 'jwksurl',
    +          type: 'text',
    +          placeholder: textPlaceholder,
    +          size: 12,
    +          validations: {
    +            required: false,
    +          },
    +        },
    +      ],
     
           [
             {
    
  • packages/plugins/users-permissions/server/services/providers-registry.js+5 6 modified
    @@ -4,7 +4,7 @@ const { strict: assert } = require('assert');
     const jwt = require('jsonwebtoken');
     const jwkToPem = require('jwk-to-pem');
     
    -const getCognitoPayload = async (idToken, purest) => {
    +const getCognitoPayload = async ({ idToken, jwksUrl, purest }) => {
       const {
         header: { kid },
         payload,
    @@ -14,12 +14,10 @@ const getCognitoPayload = async (idToken, purest) => {
         throw new Error('The provided token is not valid');
       }
     
    -  const { iss } = payload;
    -
       const config = {
         cognito: {
           discovery: {
    -        origin: `${iss}/.well-known/jwks.json`,
    +        origin: jwksUrl,
             path: '',
           },
         },
    @@ -63,9 +61,10 @@ const getInitialProviders = ({ purest }) => ({
             };
           });
       },
    -  async cognito({ query }) {
    +  async cognito({ query, providers }) {
    +    const jwksUrl = providers.cognito.jwksurl;
         const idToken = query.id_token;
    -    const tokenPayload = await getCognitoPayload(idToken, purest);
    +    const tokenPayload = await getCognitoPayload({ idToken, jwksUrl, purest });
         return {
           username: tokenPayload['cognito:username'],
           email: tokenPayload.email,
    
46f8f9837833

Verify cognito token with AWS

https://github.com/strapi/strapiChristian CapeansJan 9, 2023via ghsa
3 files changed · +53 12
  • packages/plugins/users-permissions/package.json+1 0 modified
    @@ -32,6 +32,7 @@
         "bcryptjs": "2.4.3",
         "grant-koa": "5.4.8",
         "jsonwebtoken": "^8.1.0",
    +    "jwk-to-pem": "2.0.5",
         "koa": "^2.13.4",
         "koa2-ratelimit": "^1.1.2",
         "lodash": "4.17.21",
    
  • packages/plugins/users-permissions/server/services/providers-registry.js+49 11 modified
    @@ -2,6 +2,50 @@
     
     const { strict: assert } = require('assert');
     const jwt = require('jsonwebtoken');
    +const jwkToPem = require('jwk-to-pem');
    +
    +const getCognitoPayload = async (idToken, purest) => {
    +  const {
    +    header: { kid },
    +    payload,
    +  } = jwt.decode(idToken, { complete: true });
    +
    +  if (!payload || !kid) {
    +    throw new Error('The provided token is not valid');
    +  }
    +
    +  const { iss } = payload;
    +
    +  const config = {
    +    cognito: {
    +      discovery: {
    +        origin: `${iss}/.well-known/jwks.json`,
    +        path: '',
    +      },
    +    },
    +  };
    +  try {
    +    const cognito = purest({ provider: 'cognito', config });
    +    // get the JSON Web Key (JWK) for the user pool
    +    const { body: jwk } = await cognito('discovery').request();
    +    // Get the key with the same Key ID as the provided token
    +    const key = jwk.keys.find(({ kid: jwkKid }) => jwkKid === kid);
    +    const pem = jwkToPem(key);
    +
    +    // https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
    +    const decodedToken = await new Promise((resolve, reject) => {
    +      jwt.verify(idToken, pem, { algorithms: ['RS256'] }, (err, decodedToken) => {
    +        if (err) {
    +          reject();
    +        }
    +        resolve(decodedToken);
    +      });
    +    });
    +    return decodedToken;
    +  } catch (err) {
    +    throw new Error('There was an error verifying the token');
    +  }
    +};
     
     const getInitialProviders = ({ purest }) => ({
       async discord({ accessToken }) {
    @@ -20,18 +64,12 @@ const getInitialProviders = ({ purest }) => ({
           });
       },
       async cognito({ query }) {
    -    // get the id_token
         const idToken = query.id_token;
    -    // decode the jwt token
    -    const tokenPayload = jwt.decode(idToken);
    -    if (!tokenPayload) {
    -      throw new Error('unable to decode jwt token');
    -    } else {
    -      return {
    -        username: tokenPayload['cognito:username'],
    -        email: tokenPayload.email,
    -      };
    -    }
    +    const tokenPayload = await getCognitoPayload(idToken, purest);
    +    return {
    +      username: tokenPayload['cognito:username'],
    +      email: tokenPayload.email,
    +    };
       },
       async facebook({ accessToken }) {
         const facebook = purest({ provider: 'facebook' });
    
  • yarn.lock+3 1 modified
    @@ -15118,7 +15118,7 @@ jwa@^2.0.0:
         ecdsa-sig-formatter "1.0.11"
         safe-buffer "^5.0.1"
     
    -jwk-to-pem@^2.0.5:
    +jwk-to-pem@2.0.5, jwk-to-pem@^2.0.5:
       version "2.0.5"
       resolved "https://registry.yarnpkg.com/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz#151310bcfbcf731adc5ad9f379cbc8b395742906"
       integrity sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==
    @@ -18081,6 +18081,8 @@ path-case@^2.1.0:
       version "2.1.1"
       resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
       integrity sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=
    +  dependencies:
    +    no-case "^2.2.0"
     
     path-dirname@^1.0.0:
       version "1.0.2"
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.