Skip to content

Conversation

@kkartunov
Copy link
Collaborator

Reverts #7052

@kkartunov kkartunov merged commit d1a2dcb into master Jan 29, 2025
2 of 3 checks passed
return this.getSheetAPI(req, res);
}
res.status(status);
return res.send((e.response && e.response.data) || { ...e, message: e.message });

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
Comment on lines +31 to +37
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}`, {
method: 'GET',
headers: {
'Content-Type': req.headers['content-type'],
Authorization: this.authorization,
},
});

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.
The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI 12 months ago

To fix the problem, we need to validate and sanitize the user-provided values (listId and emailHash) before incorporating them into the URL. We can use a whitelist approach to ensure that only valid listId values are accepted. For emailHash, we can validate it using a regular expression to ensure it conforms to the expected format.

  1. Create a whitelist of valid listId values.
  2. Validate the emailHash using a regular expression.
  3. If the values are not valid, return an error response instead of making the request.
Suggested changeset 1
src/server/services/mailchimp.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/server/services/mailchimp.js b/src/server/services/mailchimp.js
--- a/src/server/services/mailchimp.js
+++ b/src/server/services/mailchimp.js
@@ -22,2 +22,3 @@
     this.authorization = `Basic ${Buffer.from(`apikey:${this.apiKey}`).toString('base64')}`;
+    this.validListIds = ['list1', 'list2', 'list3']; // Example whitelist of valid list IDs
   }
@@ -30,3 +31,7 @@
   async checkSubscription(req) {
-    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}`, {
+    const { listId, emailHash } = req.params;
+    if (!this.isValidListId(listId) || !this.isValidEmailHash(emailHash)) {
+      throw new Error('Invalid parameters');
+    }
+    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}`, {
       method: 'GET',
@@ -110,2 +115,11 @@
   }
+
+  isValidListId(listId) {
+    return this.validListIds.includes(listId);
+  }
+
+  isValidEmailHash(emailHash) {
+    const emailHashRegex = /^[a-f0-9]{32}$/; // Example regex for validating email hash
+    return emailHashRegex.test(emailHash);
+  }
 }
EOF
@@ -22,2 +22,3 @@
this.authorization = `Basic ${Buffer.from(`apikey:${this.apiKey}`).toString('base64')}`;
this.validListIds = ['list1', 'list2', 'list3']; // Example whitelist of valid list IDs
}
@@ -30,3 +31,7 @@
async checkSubscription(req) {
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}`, {
const { listId, emailHash } = req.params;
if (!this.isValidListId(listId) || !this.isValidEmailHash(emailHash)) {
throw new Error('Invalid parameters');
}
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}`, {
method: 'GET',
@@ -110,2 +115,11 @@
}

isValidListId(listId) {
return this.validListIds.includes(listId);
}

isValidEmailHash(emailHash) {
const emailHashRegex = /^[a-f0-9]{32}$/; // Example regex for validating email hash
return emailHashRegex.test(emailHash);
}
}
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +43 to +50
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members`, {
method: 'POST',
headers: {
'Content-Type': req.headers['content-type'],
Authorization: this.authorization,
},
body: formData,
});

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI 12 months ago

To fix the SSRF vulnerability, we need to validate and sanitize the listId parameter before using it in the URL. One way to do this is to use a whitelist of allowed listId values or to ensure that the listId conforms to a specific pattern expected by the Mailchimp API. This will prevent attackers from injecting malicious values into the URL.

We will implement a validation function that checks if the listId is in a predefined list of allowed values. If the listId is not valid, we will throw an error or handle it appropriately.

Suggested changeset 1
src/server/services/mailchimp.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/server/services/mailchimp.js b/src/server/services/mailchimp.js
--- a/src/server/services/mailchimp.js
+++ b/src/server/services/mailchimp.js
@@ -22,2 +22,3 @@
     this.authorization = `Basic ${Buffer.from(`apikey:${this.apiKey}`).toString('base64')}`;
+    this.allowedListIds = ['list1', 'list2', 'list3']; // Example allowed list IDs
   }
@@ -42,3 +43,4 @@
     const formData = JSON.stringify(req.body);
-    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members`, {
+    const listId = this.validateListId(req.params.listId);
+    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members`, {
       method: 'POST',
@@ -110,2 +112,9 @@
   }
+  validateListId(listId) {
+    if (this.allowedListIds.includes(listId)) {
+      return listId;
+    } else {
+      throw new Error('Invalid list ID');
+    }
+  }
 }
EOF
@@ -22,2 +22,3 @@
this.authorization = `Basic ${Buffer.from(`apikey:${this.apiKey}`).toString('base64')}`;
this.allowedListIds = ['list1', 'list2', 'list3']; // Example allowed list IDs
}
@@ -42,3 +43,4 @@
const formData = JSON.stringify(req.body);
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members`, {
const listId = this.validateListId(req.params.listId);
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members`, {
method: 'POST',
@@ -110,2 +112,9 @@
}
validateListId(listId) {
if (this.allowedListIds.includes(listId)) {
return listId;
} else {
throw new Error('Invalid list ID');
}
}
}
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +56 to +63
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}`, {
method: 'PUT',
headers: {
'Content-Type': req.headers['content-type'],
Authorization: this.authorization,
},
body: formData,
});

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.
The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI 12 months ago

To fix the problem, we need to validate and sanitize the user-provided values (listId and emailHash) before incorporating them into the URL. We can use a whitelist approach to ensure that only valid listId values are accepted. For emailHash, we can validate it using a regular expression to ensure it conforms to the expected format.

  1. Create a whitelist of valid listId values.
  2. Validate the listId against the whitelist.
  3. Validate the emailHash using a regular expression.
Suggested changeset 1
src/server/services/mailchimp.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/server/services/mailchimp.js b/src/server/services/mailchimp.js
--- a/src/server/services/mailchimp.js
+++ b/src/server/services/mailchimp.js
@@ -30,3 +30,16 @@
   async checkSubscription(req) {
-    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}`, {
+    const validListIds = ['list1', 'list2', 'list3']; // Example whitelist
+    const listId = req.params.listId;
+    const emailHash = req.params.emailHash;
+
+    if (!validListIds.includes(listId)) {
+      throw new Error('Invalid listId');
+    }
+
+    const emailHashPattern = /^[a-f0-9]{32}$/; // Example pattern for email hash
+    if (!emailHashPattern.test(emailHash)) {
+      throw new Error('Invalid emailHash');
+    }
+
+    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}`, {
       method: 'GET',
@@ -42,3 +55,10 @@
     const formData = JSON.stringify(req.body);
-    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members`, {
+    const validListIds = ['list1', 'list2', 'list3']; // Example whitelist
+    const listId = req.params.listId;
+
+    if (!validListIds.includes(listId)) {
+      throw new Error('Invalid listId');
+    }
+
+    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members`, {
       method: 'POST',
@@ -55,3 +75,16 @@
     const formData = JSON.stringify(req.body);
-    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}`, {
+    const validListIds = ['list1', 'list2', 'list3']; // Example whitelist
+    const listId = req.params.listId;
+    const emailHash = req.params.emailHash;
+
+    if (!validListIds.includes(listId)) {
+      throw new Error('Invalid listId');
+    }
+
+    const emailHashPattern = /^[a-f0-9]{32}$/; // Example pattern for email hash
+    if (!emailHashPattern.test(emailHash)) {
+      throw new Error('Invalid emailHash');
+    }
+
+    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}`, {
       method: 'PUT',
@@ -68,3 +101,16 @@
     const formData = JSON.stringify(req.body);
-    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}/tags`, {
+    const validListIds = ['list1', 'list2', 'list3']; // Example whitelist
+    const listId = req.params.listId;
+    const emailHash = req.params.emailHash;
+
+    if (!validListIds.includes(listId)) {
+      throw new Error('Invalid listId');
+    }
+
+    const emailHashPattern = /^[a-f0-9]{32}$/; // Example pattern for email hash
+    if (!emailHashPattern.test(emailHash)) {
+      throw new Error('Invalid emailHash');
+    }
+
+    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}/tags`, {
       method: 'POST',
EOF
@@ -30,3 +30,16 @@
async checkSubscription(req) {
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}`, {
const validListIds = ['list1', 'list2', 'list3']; // Example whitelist
const listId = req.params.listId;
const emailHash = req.params.emailHash;

if (!validListIds.includes(listId)) {
throw new Error('Invalid listId');
}

const emailHashPattern = /^[a-f0-9]{32}$/; // Example pattern for email hash
if (!emailHashPattern.test(emailHash)) {
throw new Error('Invalid emailHash');
}

const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}`, {
method: 'GET',
@@ -42,3 +55,10 @@
const formData = JSON.stringify(req.body);
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members`, {
const validListIds = ['list1', 'list2', 'list3']; // Example whitelist
const listId = req.params.listId;

if (!validListIds.includes(listId)) {
throw new Error('Invalid listId');
}

const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members`, {
method: 'POST',
@@ -55,3 +75,16 @@
const formData = JSON.stringify(req.body);
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}`, {
const validListIds = ['list1', 'list2', 'list3']; // Example whitelist
const listId = req.params.listId;
const emailHash = req.params.emailHash;

if (!validListIds.includes(listId)) {
throw new Error('Invalid listId');
}

const emailHashPattern = /^[a-f0-9]{32}$/; // Example pattern for email hash
if (!emailHashPattern.test(emailHash)) {
throw new Error('Invalid emailHash');
}

const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}`, {
method: 'PUT',
@@ -68,3 +101,16 @@
const formData = JSON.stringify(req.body);
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}/tags`, {
const validListIds = ['list1', 'list2', 'list3']; // Example whitelist
const listId = req.params.listId;
const emailHash = req.params.emailHash;

if (!validListIds.includes(listId)) {
throw new Error('Invalid listId');
}

const emailHashPattern = /^[a-f0-9]{32}$/; // Example pattern for email hash
if (!emailHashPattern.test(emailHash)) {
throw new Error('Invalid emailHash');
}

const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}/tags`, {
method: 'POST',
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +69 to +76
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}/tags`, {
method: 'POST',
headers: {
'Content-Type': req.headers['content-type'],
Authorization: this.authorization,
},
body: formData,
});

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.
The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI 12 months ago

To fix the SSRF vulnerability, we need to validate and sanitize the user input before incorporating it into the URL. Specifically, we should ensure that req.params.listId and req.params.emailHash are valid and conform to expected patterns. This can be achieved by using a whitelist of acceptable values or by validating the format of these parameters.

  1. Validate req.params.listId and req.params.emailHash to ensure they conform to expected patterns.
  2. Reject or sanitize any input that does not match the expected patterns.
Suggested changeset 1
src/server/services/mailchimp.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/server/services/mailchimp.js b/src/server/services/mailchimp.js
--- a/src/server/services/mailchimp.js
+++ b/src/server/services/mailchimp.js
@@ -68,3 +68,10 @@
     const formData = JSON.stringify(req.body);
-    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}/tags`, {
+    const listId = req.params.listId;
+    const emailHash = req.params.emailHash;
+
+    if (!/^[a-zA-Z0-9]+$/.test(listId) || !/^[a-f0-9]{32}$/.test(emailHash)) {
+      throw new Error('Invalid listId or emailHash');
+    }
+
+    const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}/tags`, {
       method: 'POST',
EOF
@@ -68,3 +68,10 @@
const formData = JSON.stringify(req.body);
const res = await fetch(`${this.mailchimpBaseUrl}/lists/${req.params.listId}/members/${req.params.emailHash}/tags`, {
const listId = req.params.listId;
const emailHash = req.params.emailHash;

if (!/^[a-zA-Z0-9]+$/.test(listId) || !/^[a-f0-9]{32}$/.test(emailHash)) {
throw new Error('Invalid listId or emailHash');
}

const res = await fetch(`${this.mailchimpBaseUrl}/lists/${listId}/members/${emailHash}/tags`, {
method: 'POST',
Copilot is powered by AI and may make mistakes. Always verify output.
kkartunov added a commit that referenced this pull request Jan 30, 2025
…evelop"

This reverts commit d1a2dcb, reversing
changes made to 1c912fb.
kkartunov added a commit that referenced this pull request Jan 30, 2025
…evelop"

This reverts commit d1a2dcb, reversing
changes made to 1c912fb.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants