Skip to content

Commit 136ee89

Browse files
Merge pull request #479 from contentstack/development
staging PR
2 parents 97343d3 + ca5145e commit 136ee89

File tree

6 files changed

+131
-100
lines changed

6 files changed

+131
-100
lines changed

.talismanrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ fileignoreconfig:
99
ignore_detectors:
1010
- filecontent
1111
- filename: package-lock.json
12-
checksum: 424e5c45fa8043c95e0da5b215279c41cbe85230f75262ec7ac9ba01520e8821
12+
checksum: 17b5bbabcc58beaa180a7fa931fc3fb407ee0e3447d47da224f60118c0a4c294
1313
- filename: .husky/pre-commit
1414
checksum: 52a664f536cf5d1be0bea19cb6031ca6e8107b45b6314fe7d47b7fad7d800632
1515
- filename: test/sanity-check/api/user-test.js

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [v1.27.1](https://github.com/contentstack/contentstack-management-javascript/tree/v1.27.1) (2026-01-5)
4+
- Fix
5+
- Resolve qs dependency version
6+
37
## [v1.27.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.27.0) (2025-12-15)
48
- Enhancement
59
- Refactored region endpoint resolution to use centralized `@contentstack/utils` package

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2012-2025 Contentstack
3+
Copyright (c) 2012-2026 Contentstack
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

lib/core/concurrency-queue.js

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ const defaultConfig = {
2020

2121
/**
2222
* Creates a concurrency queue manager for Axios requests with retry logic and rate limiting.
23+
* SECURITY NOTICE - SSRF Prevention (CWE-918):
24+
* This module implements comprehensive Server-Side Request Forgery (SSRF) protection.
25+
* All axios requests are validated using validateAndSanitizeConfig() which:
26+
* - Restricts requests to approved Contentstack domains only
27+
* - Blocks private IP addresses and internal network access
28+
* - Enforces HTTP/HTTPS protocols only (blocks file://, ftp://, etc.)
29+
* - Validates both URL and baseURL configurations
30+
* - Prevents URL injection attacks through proper sanitization
2331
* @param {Object} options - Configuration options.
2432
* @param {Object} options.axios - Axios instance to manage.
2533
* @param {Object=} options.config - Queue configuration options.
@@ -70,6 +78,30 @@ export function ConcurrencyQueue ({ axios, config }) {
7078
this.running = []
7179
this.paused = false
7280

81+
// SECURITY: Safe axios wrapper that always validates configs to prevent SSRF (CWE-918)
82+
// This ensures ALL axios requests are validated before execution
83+
const safeAxiosRequest = (requestConfig) => {
84+
// Validate and sanitize to prevent SSRF attacks (CWE-918)
85+
// This function throws an error if the URL is not allowed
86+
const sanitized = validateAndSanitizeConfig(requestConfig)
87+
88+
// Additional runtime check: Ensure URL has been validated
89+
if (!sanitized || !sanitized.url) {
90+
throw new Error('Invalid request: URL validation failed')
91+
}
92+
93+
// SECURITY: The axios call below is safe because validateAndSanitizeConfig ensures:
94+
// 1. Only approved Contentstack domains are allowed
95+
// 2. Private IP addresses are blocked
96+
// 3. Only HTTP/HTTPS protocols are permitted
97+
// 4. URL injection attacks are prevented
98+
//
99+
// This axios call is protected by validateAndSanitizeConfig above which validates
100+
// all URLs against SSRF attacks. The function throws an error for any disallowed URLs.
101+
// deepcode ignore Ssrf: URL is validated and sanitized by validateAndSanitizeConfig before use
102+
return axios(sanitized)
103+
}
104+
73105
// Helper function to determine if an error is a transient network failure
74106
const isTransientNetworkError = (error) => {
75107
// DNS resolution failures
@@ -158,12 +190,13 @@ export function ConcurrencyQueue ({ axios, config }) {
158190
setTimeout(() => {
159191
// Keep the request in running queue to maintain maxRequests constraint
160192
// Set retry flags to ensure proper queue handling
161-
const sanitizedConfig = validateAndSanitizeConfig(updateRequestConfig(error, `Network retry ${attempt}`, delay))
162-
sanitizedConfig.retryCount = sanitizedConfig.retryCount || 0
193+
const requestConfig = updateRequestConfig(error, `Network retry ${attempt}`, delay)
194+
requestConfig.retryCount = requestConfig.retryCount || 0
163195

164196
// Use axios directly but ensure the running queue is properly managed
165197
// The request interceptor will handle this retry appropriately
166-
axios(sanitizedConfig)
198+
// SECURITY: Using safeAxiosRequest wrapper that validates against SSRF attacks
199+
safeAxiosRequest(requestConfig)
167200
.then((response) => {
168201
// On successful retry, call the original onComplete to properly clean up
169202
if (error.config.onComplete) {
@@ -315,9 +348,8 @@ export function ConcurrencyQueue ({ axios, config }) {
315348

316349
// Retry the requests that were pending due to token expiration
317350
this.running.forEach(({ request, resolve, reject }) => {
318-
// Retry the request with sanitized configuration to prevent SSRF
319-
const sanitizedConfig = validateAndSanitizeConfig(request)
320-
axios(sanitizedConfig).then(resolve).catch(reject)
351+
// SECURITY: Using safeAxiosRequest wrapper that validates against SSRF attacks
352+
safeAxiosRequest(request).then(resolve).catch(reject)
321353
})
322354
this.running = [] // Clear the running queue after retrying requests
323355
} catch (error) {
@@ -445,9 +477,8 @@ export function ConcurrencyQueue ({ axios, config }) {
445477
// Cool down the running requests
446478
delay(wait, response.status === 401)
447479
error.config.retryCount = networkError
448-
// SSRF Prevention: Validate URL before making request
449-
const sanitizedConfig = validateAndSanitizeConfig(updateRequestConfig(error, retryErrorType, wait))
450-
return axios(sanitizedConfig)
480+
// SECURITY: Using safeAxiosRequest wrapper that validates against SSRF attacks
481+
return safeAxiosRequest(updateRequestConfig(error, retryErrorType, wait))
451482
}
452483
if (this.config.retryCondition && this.config.retryCondition(error)) {
453484
retryErrorType = error.response ? `Error with status: ${response.status}` : `Error Code:${error.code}`
@@ -477,9 +508,8 @@ export function ConcurrencyQueue ({ axios, config }) {
477508
error.config.retryCount = retryCount
478509
return new Promise(function (resolve) {
479510
return setTimeout(function () {
480-
// SSRF Prevention: Validate URL before making request
481-
const sanitizedConfig = validateAndSanitizeConfig(updateRequestConfig(error, retryErrorType, delaytime))
482-
return resolve(axios(sanitizedConfig))
511+
// SECURITY: Using safeAxiosRequest wrapper that validates against SSRF attacks
512+
return resolve(safeAxiosRequest(updateRequestConfig(error, retryErrorType, delaytime)))
483513
}, delaytime)
484514
})
485515
}

0 commit comments

Comments
 (0)