Thanks to 2 community members and some of our internal team, we have been notified and patched two security vulnerabilities:
Per our security policy, we are performing our due diligence by publicly disclosing these vulnerabilities after careful testing, validation, communication, and our mandatory waiting period. For further details of the patched vulnerabilities, please refer to the information below or consult the linked GitHub Advisories.
We would like to thank the following community members for their participation in our security program:
Likewise, a shoutout to 3 of our team members for alerting us to CVE-2023-34093.
To immediately resolve all vulnerabilities detailed in this post, please update all of your Strapi packages to version >=4.11.4.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
This vulnerability bypassed previous fixes to our sanitization system by using functions provided by Knex on relational joins. By forcefully injecting SQL join syntax such as t0
, t1
, etc. you could effectively fetch private field data such as password reset tokens. An example of such filtering syntax would be as such:
localhost:1338/api/tests?filters[updatedBy][t1.email][$startsWith]=test2&populate=*
We resolved this issue by forcing request sanitization to limit filters only to attributes that exist within the content-type and strictly removing any filters that are not allowed (such as private fields). Due to the extremely complex nature of this vulnerability and the requirement to have either relations set up to a content-type containing private fields or creator fields enabled on a content-type, we do not believe this vulnerability was actively used in the wild before disclosure.
We advise reviewing your Strapi application logs and searching for any references to [t0.
, [t1.
, etc. to determine if such filters were attempted to be used against your application. You can use the following regex pattern when reviewing your application logs: filters.*(\[|%5B)\s*t\d+\.(email|password|reset_password_token|resetPasswordToken)\s*(\]|%5D)
.
Time | Event |
---|---|
2023/05/02 5:46pm GMT | Report of the vulnerability received by the Strapi Security Team |
2023/05/05 8:15am GMT | Vulnerability report was accepted by the Strapi Team |
2023/05/05 11:27am GMT | The Strapi Engineering Team communicated to the reporter our planned changes to get their feedback |
2023/05/07 5:30pm GMT | The reporter acknowledged and agreed with our planned changes |
2023/06/07 8:12am GMT | An experimental release was made with the changes communicated previously for testing |
2023/06/07 3:42pm GMT | GitHub issued CVE-2023-34235 per our request |
2023/06/07 1:08pm GMT | Patch was released in Strapi version v4.10.8 |
2023/06/07 3:00pm GMT | Disclosure communication placed on hold due to internal requirements and other vulnerability work being performed |
2023/07/10 7:25pm GMT | Initial warning email was sent out to all Strapi Enterprise and Cloud Customers including Strapi partners with active enterprise contracts |
2023/07/10 7:25pm GMT | Mandatory waiting period of 2 weeks initiated |
2023/07/25 1:01pm GMT | Released the full disclosure of the vulnerability and published GitHub Advisories |
2023/07/25 1:01pm GMT | Disclosure email was sent out to all Strapi Enterprise and Cloud Customers, including Strapi partners with active enterprise contracts |
CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:L/A:N
This vulnerability only applies to Strapi Enterprise and Cloud customers. It requires specific customization to be done that extends content types during runtime (aka bootstrap functions) that copies the content-type object such as:
1strapi.container.get('content-types').extend(contentTypeUID, (contentType) => {
2 const newCT = { ... contentType, attributes: { ...contentType.attributes, newAttr: {} } };
3 return newCT;
4});
This will have the effect of removing the getter, and as we rely on it in sanitization, all attributes will be considered public. If you were extending and not copying the content-type object, then you were not affected.
Review your code if you are extending content-types at runtime to ensure you are not copying the object and instead are just mutating it. If you have not done any such customization, then you are not impacted. A proper example of extending a content-type is as such:
1strapi.container.get('content-types').extend(contentTypeUID, (contentType) => newContentType);
Time | Event |
---|---|
2023/05/30 3:23pm GMT | Report of the vulnerability received by the Strapi Security Team via an internal source |
2023/05/30 3:28pm GMT | Vulnerability report was accepted by the Strapi Team |
2023/05/31 11:08am GMT | Patch developed and pushed to internal fork for testing |
2023/06/01 1:38pm GMT | Patch verified and merged into the main codebase |
2023/06/01 2:27pm GMT | GitHub issued CVE-2023-34093 per our request |
2023/06/07 1:08pm GMT | Patch was released in Strapi version v4.10.8 |
2023/06/07 3:00pm GMT | Disclosure communication placed on hold due to internal requirements and other vulnerability work being performed |
2023/07/10 7:25pm GMT | Initial warning email was sent out to all Strapi Enterprise and Cloud Customers including Strapi partners with active enterprise contracts |
2023/07/10 7:25pm GMT | Mandatory waiting period of 2 weeks initiated |
2022/07/25 1:01pm GMT | Released the full disclosure of the vulnerability and published GitHub Advisories |
2022/07/25 1:01pm GMT | Disclosure email was sent out to all Strapi Enterprise and Cloud Customers including Strapi partners with active enterprise contracts |
We at Strapi do believe in responsible disclosure. In the case of these vulnerabilities, we have worked with the security researcher to ensure that the vulnerabilities were patched before the full disclosure of the vulnerabilities. Once a vulnerability is patched, we added a notice to our release notes to inform users there was a security vulnerability but initially wanted to delay detailed disclosure for a few weeks to give time for users to upgrade before the release of the full disclosure. As an additional step, we immediately notified our customers via several emails beforehand to ensure they were aware of the vulnerabilities and to upgrade their Strapi servers.
In this case, we believe that delaying the detailed disclosure was important to ensure that users had the time required to upgrade their Strapi servers before making the details of each vulnerability public, thus placing that information in the hands of bad actors. We also believe that the security researcher was very professional and responsible in handling the vulnerabilities, and we are very thankful for their work in helping us improve the security of Strapi.
We urge anyone who believes they have discovered a security vulnerability to assist us in responsibly disclosing the vulnerability to us by submitting a GitHub Advisory on our main repo or by contacting our security team via security@strapi.io.
Thanks,
The Strapi Security Team