Skip to content

Commit 178671a

Browse files
authored
chore: Sanitize titles for Slack notification (#716)
chore: Sanitize titles for Slack notification - Avoid injection attacks by adding basic user input sanitation - Update dist/index.js due to failing build
1 parent 4d6b6b8 commit 178671a

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

.github/workflows/notifications.yml

+40-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,43 @@ jobs:
1313
runs-on: ubuntu-latest
1414

1515
steps:
16+
- uses: actions/github-script@v7
17+
id: sanitize-title
18+
with:
19+
script: |
20+
const isPR = !!context.payload.pull_request;
21+
const isIssue = !!context.payload.issue;
22+
const item = isPR ? context.payload.pull_request : isIssue ? context.payload.issue : context.payload.issue_comment.issue;
23+
24+
// Sanitization functions
25+
const sanitizeTitle = (title) => {
26+
return title
27+
// Remove potential markdown formatting
28+
.replace(/[*_~`]/g, '')
29+
// Remove potential HTML tags
30+
.replace(/<[^>]*>/g, '')
31+
// Remove multiple spaces
32+
.replace(/\s{2,}/g, ' ')
33+
// Trim whitespace
34+
.trim()
35+
// Enforce max length of 100
36+
.substring(0, 100);
37+
};
38+
39+
// Escape special characters for Slack
40+
const escapeForSlack = (text) => {
41+
return text
42+
.replace(/&/g, '&amp;')
43+
.replace(/</g, '&lt;')
44+
.replace(/[@]/g, '\\@')
45+
.replace(/>/g, '&gt;')
46+
.replace(/&amp;lt;/g, '&lt;')
47+
.replace(/&amp;gt;/g, '&gt;');
48+
};
49+
50+
const sanitizedTitle = escapeForSlack(sanitizeTitle(item.title));
51+
console.log('Sanitized Title: ', sanitizedTitle);
52+
core.setOutput('safe-title', sanitizedTitle);
1653
- name: Send notifications on Pull Request
1754
if: ${{ github.event_name == 'pull_request'}}
1855
id: slack_PR
@@ -23,7 +60,7 @@ jobs:
2360
"Notification Type": "Pull Request",
2461
"Notification URL":"${{ github.event.pull_request.html_url }}",
2562
"GitHub Repo": "${{ github.repository }}",
26-
"Notification Title": "${{ github.event.pull_request.title }}"
63+
"Notification Title": "${{ steps.sanitize-title.outputs.safe-title }}"
2764
}
2865
env:
2966
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
@@ -37,7 +74,7 @@ jobs:
3774
"Notification Type": "Issue",
3875
"Notification URL":"${{ github.event.issue.html_url }}",
3976
"GitHub Repo": "${{ github.repository }}",
40-
"Notification Title": "${{ github.event.issue.title }}"
77+
"Notification Title": "${{ steps.sanitize-title.outputs.safe-title }}"
4178
}
4279
env:
4380
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
@@ -51,7 +88,7 @@ jobs:
5188
"Notification Type": "Issue comment",
5289
"Notification URL":"${{ github.event.comment.html_url }}",
5390
"GitHub Repo": "${{ github.repository }}",
54-
"Notification Title": "${{ github.event.issue_comment.issue.title }}"
91+
"Notification Title": "${{ steps.sanitize-title.outputs.safe-title }}"
5592
}
5693
env:
5794
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

dist/index.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -78456,6 +78456,14 @@ const { isUint8Array, isArrayBuffer } = __nccwpck_require__(98253)
7845678456
const { File: UndiciFile } = __nccwpck_require__(63041)
7845778457
const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(94322)
7845878458

78459+
let random
78460+
try {
78461+
const crypto = __nccwpck_require__(77598)
78462+
random = (max) => crypto.randomInt(0, max)
78463+
} catch {
78464+
random = (max) => Math.floor(Math.random(max))
78465+
}
78466+
7845978467
let ReadableStream = globalThis.ReadableStream
7846078468

7846178469
/** @type {globalThis['File']} */
@@ -78541,7 +78549,7 @@ function extractBody (object, keepalive = false) {
7854178549
// Set source to a copy of the bytes held by object.
7854278550
source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
7854378551
} else if (util.isFormDataLike(object)) {
78544-
const boundary = `----formdata-undici-0${`${Math.floor(Math.random() * 1e11)}`.padStart(11, '0')}`
78552+
const boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, '0')}`
7854578553
const prefix = `--${boundary}\r\nContent-Disposition: form-data`
7854678554

7854778555
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
@@ -93357,6 +93365,14 @@ module.exports = require("node:buffer");
9335793365

9335893366
/***/ }),
9335993367

93368+
/***/ 77598:
93369+
/***/ ((module) => {
93370+
93371+
"use strict";
93372+
module.exports = require("node:crypto");
93373+
93374+
/***/ }),
93375+
9336093376
/***/ 78474:
9336193377
/***/ ((module) => {
9336293378

0 commit comments

Comments
 (0)