Jun 20, 2026·6 min read·9 visits
The @jhb.software/payload-cloudinary-plugin fails to validate client-supplied parameters passed to Cloudinary's cryptographic signing helper. Authenticated users can obtain mathematically valid HMAC-SHA1 signatures for any arbitrary payload, creating a signature oracle to overwrite files, bypass visibility rules, or trigger outbound SSRF webhooks.
The @jhb.software/payload-cloudinary-plugin exposes an endpoint that performs unvalidated cryptographic signing of Cloudinary API parameters, allowing authenticated users with minimal privileges to forge valid signatures for arbitrary actions. This flaw allows attackers to overwrite remote storage assets, execute unauthorized file uploads, alter asset visibility parameters, trigger SSRF webhooks, and perform directory traversal within Cloudinary repositories.
The module @jhb.software/payload-cloudinary-plugin integrates Cloudinary cloud storage within Payload CMS architectures. When configured with client-side direct uploads enabled (clientUploads: true), the application registers a dedicated backend route designed to handle request signing. This design optimizes payload delivery by transferring large binary media uploads directly from the client browser to Cloudinary's infrastructure, reducing CPU usage and bandwidth consumption on the primary application server.\n\nBecause direct client-side uploads require authentication, Cloudinary relies on cryptographic signatures generated with a private API secret key. The plugin mounts a server-side route designed to accept upload parameters from clients, compute the corresponding HMAC-SHA1 signature, and return it to the browser. However, the endpoint acts as an unrestricted signing oracle because it lacks input sanitization, key whitelisting, or parameter verification mechanisms.\n\nAny user possessing a valid, low-privilege authentication token for the Payload CMS instance can make requests to this signing endpoint. By supplying arbitrary parameter blocks, the client forces the server to return valid cryptographic signatures. This interaction enables unauthorized asset modification, access-control subversion, and Server-Side Request Forgery within the context of the associated Cloudinary subscription.
The cryptographic security model of Cloudinary requires that upload payloads match a specific signature generated via the API_SECRET token. The signature calculation sorts the designated keys in alphabetical order, concatenates key-value pairs with ampersands, appends the secret token, and executes an SHA-1 hashing algorithm. Because the secret key must remain hidden from client-side runtime environments, the server is tasked with acting as a trusted helper to perform signature creation.\n\nIn vulnerable versions of the plugin, specifically up to version 0.3.4, the implementation in cloudinary/src/getGenerateSignature.ts fails to validate the keys contained in the request. The application registers the HTTP POST endpoint /api/cloudinary-generate-signature and binds it to a handler that reads the JSON payload directly. It parses the object named paramsToSign provided in the HTTP request body and transfers it directly to the native Cloudinary SDK utility helper.\n\nThe vulnerable sink is found at line 55 of getGenerateSignature.ts, where the application executes cloudinary.utils.api_sign_request(body.paramsToSign, apiSecret). Because there is no schema enforcement or restriction on the dictionary keys, the server signs any values submitted by the client. The absence of validation checks means parameter injection is trivially accomplished, breaking the security boundary between client and server.
An analysis of the source code changes between the vulnerable and patched versions reveals the exact mechanism of the flaw and its remediation. In the vulnerable codebase, the handler parses the request body and processes the parameters without checking for malicious inputs or unauthorized keys:\n\ntypescript\n// Vulnerable Implementation in getGenerateSignature.ts\nconst body = await req.json?.()\nconst signature = cloudinary.utils.api_sign_request(body.paramsToSign, apiSecret)\n\n\nIn contrast, the patched version introduces a strict validation pattern to protect the signature generation flow. The update restricts input keys, validates the format of fields, and blocks structural traversal attempts:\n\ntypescript\n// Patched Implementation in getGenerateSignature.ts\nconst paramsToSign = body.paramsToSign as Record<string, unknown>\nconst allowedKeys = new Set(['timestamp', 'folder', 'public_id'])\nif (\n !paramsToSign ||\n Object.keys(paramsToSign).some((key) => !allowedKeys.has(key)) ||\n typeof paramsToSign.timestamp !== 'string'\n) {\n throw new Forbidden()\n}\nif (folder && paramsToSign.folder !== folder.replace(/^\/|\/$/g, '')) {\n throw new Forbidden()\n}\nif (\n typeof paramsToSign.public_id === 'string' &&\n (paramsToSign.public_id.includes('..') || paramsToSign.public_id.startsWith('/'))\n) {\n throw new Forbidden()\n}\nconst signature = cloudinary.utils.api_sign_request(paramsToSign, apiSecret)\n\n\nThe patch enforces strict security controls: first, it checks incoming parameters against an allowed whitelist of timestamp, folder, and public_id, rejecting any unexpected options. Second, it requires the timestamp to be a string value. Third, it validates the folder parameter against the plugin config, preventing directory manipulation. Fourth, it blocks path-traversal strings like .. and root-relative prefix symbols / within public_id parameters. This blocks attempts to access directories outside of the configured folder structure.
Exploiting this signature oracle requires an attacker to possess any valid, low-privilege authentication token for the target Payload CMS system. Since the default route-level authorization only validates session existence (!!req.user), an authenticated guest or low-privilege editor can access the endpoint. The attacker must also retrieve the public Cloudinary parameters, such as the api_key and cloud_name, which are exposed to the client by design in index.ts to facilitate uploads.\n\nThe attacker sends a structured HTTP POST request to /api/cloudinary-generate-signature containing their desired target parameters inside the paramsToSign property. To overwrite an existing asset, the attacker generates an exploit payload containing overwrite=true, the targeted file's public_id, and a current unix timestamp. The backend server signs this payload and returns the valid HMAC-SHA1 signature.\n\nWith the generated signature, the attacker bypasses the application server entirely and transmits the forged payload directly to Cloudinary's API. The remote storage provider validates the signature against its own cryptographic keys, accepts the request, and overwrites the specified high-value media file. The automated Python script in this report demonstrates how to perform these operations, verifying that returned signatures match the expected cryptographic format.
The security implications of an unrestricted signature oracle on a Cloudinary account are extensive. Integrity is compromised because an attacker can overwrite arbitrary media files, which can lead to web application defacement, malicious file distribution, or database corruption if media metadata is parsed dynamically. This allows attackers to replace legitimate assets with spoofed or exploit-carrying files.\n\nFurthermore, the vulnerability introduces a network-level Server-Side Request Forgery risk. An attacker can request a signature that includes the notification_url parameter, pointing to a server under their control. When Cloudinary completes an upload transaction, its backend servers will make an outbound HTTP POST request to the attacker's server, leaking internal file-processing data or metadata.\n\nAdditionally, attackers can perform directory traversal attacks and invalidate CDN caches. By combining path-traversal sequences in the folder parameter with the invalidate=true option, an attacker can delete cached media resources from global CDN edge caches. This can increase administrative costs and degrade application performance, leading to a denial of service.
To remediate this vulnerability, system administrators and developers must upgrade @jhb.software/payload-cloudinary-plugin to version 0.4.0 or higher. This update introduces the parameter validation and path-filtering controls necessary to secure the signing endpoint. After updating, verify that configuration values for default storage paths are correctly populated in the plugin's initialization block.\n\nIf an immediate package upgrade is not feasible, client-side uploads can be disabled by setting clientUploads: false in the plugin's configuration options. This forces all media uploads to process directly through the Payload CMS backend, eliminating the risk associated with the signature generation endpoint. While this increases server bandwidth and processing load, it removes the attack surface.\n\nWeb Application Firewalls can also be configured to block malicious requests targeting this vulnerability. Define rules to monitor POST requests directed to /api/cloudinary-generate-signature and block payloads containing unauthorized parameters such as overwrite, notification_url, invalidate, or directory-traversal characters in the paramsToSign block. This provides defense-in-depth while the application is being upgraded.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
@jhb.software/payload-cloudinary-plugin jhb-software | >= 0.3.0 < 0.4.0 | 0.4.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-347 (Improper Verification of Cryptographic Signature) |
| Attack Vector | Network (Unauthenticated or Low-Privilege authenticated API interaction) |
| CVSS Score | 7.1 (High) |
| Impact | Integrity Loss, Server-Side Request Forgery, Directory Traversal, CDN Invalidation |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
The software does not verify or incorrectly verifies the cryptographic signature for data.
CVE-2026-69262 is a high-severity incorrect authorization vulnerability (CWE-863) within the Flowise drag-and-drop LLM flow platform. Prior to version 3.1.3, Flowise did not enforce resource-type validation on its deletion endpoint. Although routing middleware ensured users held deletion privileges for either chatflows or agentflows, the service level lacked validation checks to verify whether the target resource matched the user's specific permissions. Consequently, an authenticated user with only agentflow deletion permissions could delete arbitrary chatflow configurations, leading to unauthorized state modification and service disruption.
CVE-2026-69258 is a high-severity property injection and unauthenticated authorization bypass vulnerability in Flowise, a drag-and-drop orchestration interface for building customized LLM workflows. In affected versions prior to 3.1.3, the unauthenticated prediction API endpoint (`POST /api/v1/prediction/:id`) processed client-controlled parameters inside an `overrideConfig` payload without authorization checks. The backend unconditionally spread this object into internal context structures, enabling unauthenticated remote attackers to overwrite critical session values, pollute execution contexts, and bypass flow restrictions.
CVE-2026-69252 represents a missing authorization check (CWE-862) in the files API route (`/api/v1/files`) of Flowise, a drag-and-drop user interface for building LLM flows. Prior to version 3.1.3, an authenticated API key or user could list, access, and delete files across arbitrary workspaces inside an organization, completely bypassing workspace logical boundaries.
A comprehensive technical analysis of CVE-2026-45584, a high-severity heap-based buffer overflow in Microsoft Defender's QEX parsing logic. The vulnerability resides within mpengine.dll and allows unauthenticated remote code execution or denial of service when processing crafted archives designed to trigger threat remediation and QEX history logging.
A medium-severity vulnerability in Undici's retry interceptor causes body-length mismatches with the Content-Length header during HTTP 206 response resumption. Forwarding these inconsistent headers downstream leads to HTTP response desynchronization, connection hangs, or potential protocol smuggling.
CVE-2026-16729 (GHSA-v3r7-h72x-cjcm) is a medium-severity cookie attribute injection vulnerability in Undici's web-compliant cookie utility module. Due to insufficient validation of domain parameters and raw attributes in the unparsed options array, arbitrary attributes like SameSite, HttpOnly, and Secure can be injected. This allows attackers to bypass CSRF protections, strip security flags, or override intended cookie behaviors when applications pass user-controlled values to these properties.