You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

cloudinary

Package Overview
Dependencies
Maintainers
1
Versions
120
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cloudinary - npm Package Compare versions

Comparing version

to
2.7.0

5

CHANGELOG.md

@@ -0,1 +1,6 @@

2.7.0 / 2025-06-18
==================
* fix: prevent parameter injection via ampersand in parameter values (#709)
2.6.1 / 2025-05-05

@@ -2,0 +7,0 @@ ==================

7

lib/preloaded_file.js

@@ -27,8 +27,3 @@ let PRELOADED_CLOUDINARY_PATH, config, utils;

is_valid() {
let expected_signature;
expected_signature = utils.api_sign_request({
public_id: this.public_id,
version: this.version
}, config().api_secret);
return this.signature === expected_signature;
return utils.verify_api_response_signature(this.public_id, this.version, this.signature);
}

@@ -35,0 +30,0 @@

@@ -547,5 +547,3 @@ /**

if (base_transformations.some(isObject)) {
base_transformations = base_transformations.map(tr => utils.generate_transformation_string(
isObject(tr) ? clone(tr) : {transformation: tr}
));
base_transformations = base_transformations.map(tr => utils.generate_transformation_string(isObject(tr) ? clone(tr) : {transformation: tr}));
} else {

@@ -559,5 +557,3 @@ named_transformation = base_transformations.join(".");

} else if (isObject(effect)) {
effect = entries(effect).map(
([key, value]) => `${key}:${value}`
);
effect = entries(effect).map(([key, value]) => `${key}:${value}`);
}

@@ -639,5 +635,3 @@ let border = consumeOption(options, "border");

return `${key}_${normalize_expression(value)}`;
}).sort().concat(
variablesParam.map(([name, value]) => `${name}_${normalize_expression(value)}`)
).join(',');
}).sort().concat(variablesParam.map(([name, value]) => `${name}_${normalize_expression(value)}`)).join(',');

@@ -655,4 +649,3 @@ let transformations = entries(params)

if (responsive_width) {
let responsive_width_transformation = config().responsive_width_transformation
|| DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION;
let responsive_width_transformation = config().responsive_width_transformation || DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION;

@@ -752,23 +745,3 @@ transformations.push(utils.generate_transformation_string(clone(responsive_width_transformation)));

*/
const URL_KEYS = [
'api_secret',
'auth_token',
'cdn_subdomain',
'cloud_name',
'cname',
'format',
'long_url_signature',
'private_cdn',
'resource_type',
'secure',
'secure_cdn_subdomain',
'secure_distribution',
'shorten',
'sign_url',
'ssl_detected',
'type',
'url_suffix',
'use_root_path',
'version'
];
const URL_KEYS = ['api_secret', 'auth_token', 'cdn_subdomain', 'cloud_name', 'cname', 'format', 'long_url_signature', 'private_cdn', 'resource_type', 'secure', 'secure_cdn_subdomain', 'secure_distribution', 'shorten', 'sign_url', 'ssl_detected', 'type', 'url_suffix', 'use_root_path', 'version'];

@@ -938,5 +911,3 @@ /**

let analyticsOptions = getAnalyticsOptions(
Object.assign({}, options, sdkVersions)
);
let analyticsOptions = getAnalyticsOptions(Object.assign({}, options, sdkVersions));

@@ -1042,12 +1013,3 @@ let sdkAnalyticsSignature = getSDKAnalyticsSignature(analyticsOptions);

function unsigned_url_prefix(
source,
cloud_name,
private_cdn,
cdn_subdomain,
secure_cdn_subdomain,
cname,
secure,
secure_distribution
) {
function unsigned_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution) {
let prefix;

@@ -1122,12 +1084,41 @@ if (cloud_name.indexOf("/") === 0) {

function api_sign_request(params_to_sign, api_secret) {
let to_sign = entries(params_to_sign).filter(
([k, v]) => utils.present(v)
).map(
([k, v]) => `${k}=${toArray(v).join(",")}`
).sort().join("&");
return compute_hash(to_sign + api_secret, config().signature_algorithm || DEFAULT_SIGNATURE_ALGORITHM, 'hex');
// Encodes a parameter for safe inclusion in URL query strings (only replaces & with %26)
function encode_param(value) {
return String(value).replace(/&/g, '%26');
}
// Generates a string to be signed for API requests
function api_string_to_sign(params_to_sign, signature_version = 2) {
let params = entries(params_to_sign)
.map(([k, v]) => [String(k), Array.isArray(v) ? v.join(",") : v])
.filter(([k, v]) => v !== null && v !== undefined && v !== "");
params.sort((a, b) => a[0].localeCompare(b[0]));
let paramStrings = params.map(([k, v]) => {
const paramString = `${k}=${v}`;
return signature_version >= 2 ? encode_param(paramString) : paramString;
});
return paramStrings.join("&");
}
/**
* Signs API request parameters
* @param {Object} params_to_sign Parameters to sign
* @param {string} api_secret API secret
* @param {string|undefined|null} signature_algorithm Hash algorithm to use ('sha1' or 'sha256')
* @param {number|undefined|null} signature_version Version of signature algorithm to use:
* - Version 1: Original behavior without parameter encoding
* - Version 2+ (default): Includes parameter encoding to prevent parameter smuggling
* @return {string} Hexadecimal signature
* @private
*/
function api_sign_request(params_to_sign, api_secret, signature_algorithm = null, signature_version = null) {
if (signature_version == null) {
signature_version = config().signature_version || 2;
}
const to_sign = api_string_to_sign(params_to_sign, signature_version);
const algo = signature_algorithm || config().signature_algorithm || DEFAULT_SIGNATURE_ALGORITHM;
return compute_hash(to_sign + api_secret, algo, 'hex');
}
/**
* Computes hash from input string using specified algorithm.

@@ -1150,9 +1141,5 @@ * @private

let filtered_hash = {};
entries(hash).filter(
([k, v]) => utils.present(v)
).forEach(
([k, v]) => {
filtered_hash[k] = v.filter ? v.filter(x => x) : v;
}
);
entries(hash).filter(([k, v]) => utils.present(v)).forEach(([k, v]) => {
filtered_hash[k] = v.filter ? v.filter(x => x) : v;
});
return filtered_hash;

@@ -1175,4 +1162,6 @@ }

let apiSecret = ensureOption(options, 'api_secret');
let signature_algorithm = options.signature_algorithm;
let signature_version = options.signature_version;
params = exports.clear_blank(params);
params.signature = exports.api_sign_request(params, apiSecret);
params.signature = exports.api_sign_request(params, apiSecret, signature_algorithm, signature_version);
params.api_key = apiKey;

@@ -1569,5 +1558,3 @@ return params;

if (breakpoint_settings.transformation) {
breakpoint_settings.transformation = utils.generate_transformation_string(
clone(breakpoint_settings.transformation)
);
breakpoint_settings.transformation = utils.generate_transformation_string(clone(breakpoint_settings.transformation));
}

@@ -1582,7 +1569,5 @@ }

if (isArray(params.representations)) {
params.representations = JSON.stringify(params.representations.map(
r => ({
transformation: utils.generate_transformation_string(r.transformation)
})
));
params.representations = JSON.stringify(params.representations.map(r => ({
transformation: utils.generate_transformation_string(r.transformation)
})));
}

@@ -1612,5 +1597,3 @@ return params;

function hashToQuery(hash) {
return hashToParameters(hash).map(
([key, value]) => `${querystring.escape(key)}=${querystring.escape(value)}`
).join('&');
return hashToParameters(hash).map(([key, value]) => `${querystring.escape(key)}=${querystring.escape(value)}`).join('&');
}

@@ -1758,1 +1741,25 @@

});
/**
* Verifies an API response signature for a given public_id and version.
* Always uses signature version 1 for backward compatibility, matching the Ruby SDK.
* @param {string} public_id
* @param {string|number} version
* @param {string} signature
* @returns {boolean}
*/
function verify_api_response_signature(public_id, version, signature) {
const api_secret = config().api_secret;
const expected = exports.api_sign_request(
{
public_id,
version
},
api_secret,
null,
1
);
return signature === expected;
}
exports.verify_api_response_signature = verify_api_response_signature;

@@ -5,3 +5,3 @@ {

"description": "Cloudinary NPM for node.js integration",
"version": "2.6.1",
"version": "2.7.0",
"homepage": "https://cloudinary.com",

@@ -8,0 +8,0 @@ "license": "MIT",