Skip to content

Commit cc6e159

Browse files
authored
Merge pull request #192 from SalesforceCommerceCloud/url-fixes
@W-18131752@ URL adjustments
2 parents 26a7ccb + 3a07b91 commit cc6e159

File tree

5 files changed

+53
-2
lines changed

5 files changed

+53
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## v3.3.0
44
- Allow custom params for 'loginGuestUser', 'authorizeIDP' and custom body for 'loginRegisteredUserB2C' functions [#186](https://github.com/SalesforceCommerceCloud/commerce-sdk-isomorphic/pull/186)
55
- Add helper to encode special SCAPI characters [#189](https://github.com/SalesforceCommerceCloud/commerce-sdk-isomorphic/pull/189)
6+
- Normalize URLs to remove the possibility of path traversal from fetch calls [#192](https://github.com/SalesforceCommerceCloud/commerce-sdk-isomorphic/pull/192)
67

78
## v3.2.0
89

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@
181181
},
182182
{
183183
"path": "commerce-sdk-isomorphic-with-deps.tgz",
184-
"maxSize": "562 kB"
184+
"maxSize": "565 kB"
185185
}
186186
],
187187
"proxy": "https://SHORTCODE.api.commercecloud.salesforce.com"

scripts/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export async function updateApis(
140140
deployment: RegExp,
141141
rootPath: string
142142
): Promise<void> {
143+
/* eslint-disable-next-line no-console */
143144
console.warn('updateApis is deprecated. Use downloadLatestApis instead.');
144145

145146
const matchedApis = await download.search(`"${name}"`, deployment);

src/static/templateUrl.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,41 @@ it.each([
103103
])('combines %s, %s and %s into %s', (url, base, parameters, expected) => {
104104
expect(new TemplateURL(url, base, parameters).toString()).toBe(expected);
105105
});
106+
107+
it.each([
108+
['../simple', 'https://example.com', {}, 'https://example.com/simple'],
109+
['%2e%2e%2f/simple', 'https://example.com', {}, 'https://example.com/simple'],
110+
['%2E%2E%2F/simple', 'https://example.com', {}, 'https://example.com/simple'],
111+
[
112+
'%252e%252e%252fsimple',
113+
'https://example.com',
114+
{},
115+
'https://example.com/simple',
116+
],
117+
[
118+
'..%252e%252e%252f./simple',
119+
'https://example.com',
120+
{},
121+
'https://example.com/simple',
122+
],
123+
[
124+
'%252E%252e%252F./../%2e%2f/simple',
125+
'https://example.com',
126+
{},
127+
'https://example.com/simple',
128+
],
129+
[
130+
'simple?q=aa.aaa/',
131+
'https://example.com',
132+
{},
133+
'https://example.com/simple?q=aa.aaa/',
134+
],
135+
[
136+
'../simple/{sub}//',
137+
'https://example.com',
138+
{pathParams: {sub: 'one'}},
139+
'https://example.com/simple/one/',
140+
],
141+
])('Normalize %s path', (url, base, parameters, expected) => {
142+
expect(new TemplateURL(url, base, parameters).toString()).toBe(expected);
143+
});

src/static/templateUrl.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,22 @@ export default class TemplateURL extends URL {
8686
template: string,
8787
parameters?: PathParameters
8888
): string {
89-
return parameters
89+
let templatedUrl = parameters
9090
? template.replace(
9191
/\{([^\}]+)\}/g /* eslint-disable-line no-useless-escape */,
9292
(match, param: string) => String(parameters[param])
9393
)
9494
: template;
95+
96+
// Regex for ./ ../ and encoded variants
97+
const pathTraversalRegex =
98+
/(\.|%2e|%2E|%252e|%252E)+(\/|%2f|%2F|%252f|%252F)+/g;
99+
100+
if (templatedUrl.match(pathTraversalRegex)) {
101+
/* eslint-disable-next-line no-console */
102+
console.warn('Path traversal attempt detected. Normalizing url');
103+
templatedUrl = templatedUrl.replace(pathTraversalRegex, '');
104+
}
105+
return templatedUrl;
95106
}
96107
}

0 commit comments

Comments
 (0)