Skip to content

Commit

Permalink
🔒 fixes three critical stored XSS vulnerabilities thanks @saharshtapi
Browse files Browse the repository at this point in the history
…for reporting this

🔒 fixes a formula injection vulnerability in the Excel export functionality thanks @saharshtapi for reprorting this
❗️this is an important security release, we recommend to migrate asap, all titra versions below version 0.77.0 are considered insecure for production use
  • Loading branch information
faburem committed Jun 7, 2022
1 parent 66b5a18 commit e606b67
Show file tree
Hide file tree
Showing 13 changed files with 44 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .meteor/release
@@ -1 +1 @@
METEOR@2.7.2
METEOR@2.7.3
2 changes: 1 addition & 1 deletion .meteor/versions
Expand Up @@ -89,7 +89,7 @@ templating-compiler@1.4.1
templating-runtime@1.5.0
templating-tools@1.2.2
tracker@1.2.0
tunguska:reactive-aggregate@1.3.7
tunguska:reactive-aggregate@1.3.8
ui@1.0.13
underscore@1.0.10
url@1.3.2
Expand Down
2 changes: 1 addition & 1 deletion imports/ui/components/allprojectschart.js
Expand Up @@ -128,7 +128,7 @@ Template.allprojectschart.onRendered(() => {
colors: ['#009688', '#455A64', '#e4e4e4'],
height: 230,
data: {
labels: templateInstance.topTasks.get().map((task) => task._id),
labels: templateInstance.topTasks.get().map((task) => $('<span>').text(task._id).html()),
datasets: [{
values: templateInstance.topTasks.get().map((task) => task.count),
}],
Expand Down
15 changes: 13 additions & 2 deletions imports/ui/components/dailytimetable.js
Expand Up @@ -11,6 +11,7 @@ import {
numberWithUserPrecision,
getUserSetting,
getUserTimeUnitVerbose,
addToolTipToTableCell,
} from '../../utils/frontend_helpers'
import { i18nReady, t } from '../../utils/i18n.js'
import { dailyTimecardMapper } from '../../utils/server_method_helpers'
Expand Down Expand Up @@ -68,8 +69,18 @@ Template.dailytimetable.onRendered(() => {
width: 1,
compareValue: (cell, keyword) => [dayjs(cell, getGlobalSetting('dateformat')).toDate(), dayjs(keyword, getGlobalSetting('dateformat')).toDate()],
},
{ name: t('globals.project'), editable: false, width: 2 },
{ name: t('globals.resource'), editable: false, width: 2 },
{
name: t('globals.project'),
editable: false,
width: 2,
format: addToolTipToTableCell,
},
{
name: t('globals.resource'),
editable: false,
width: 2,
format: addToolTipToTableCell,
},
{
name: getUserTimeUnitVerbose(),
editable: false,
Expand Down
2 changes: 1 addition & 1 deletion imports/ui/components/detailtimetable.js
Expand Up @@ -36,7 +36,7 @@ function detailedDataTableMapper(entry) {
const project = Projects.findOne({ _id: entry.projectId })
const mapping = [project ? project.name : '',
dayjs.utc(entry.date).format(getGlobalSetting('dateformat')),
entry.task,
entry.task.replace(/^=/, '='),
projectUsers.findOne() ? projectUsers.findOne().users.find((elem) => elem._id === entry.userId)?.profile?.name : '']
if (getGlobalSetting('showCustomFieldsInDetails')) {
if (CustomFields.find({ classname: 'time_entry' }).count() > 0) {
Expand Down
5 changes: 3 additions & 2 deletions imports/ui/components/periodtimetable.js
Expand Up @@ -11,6 +11,7 @@ import {
numberWithUserPrecision,
getUserSetting,
getUserTimeUnitVerbose,
addToolTipToTableCell,
} from '../../utils/frontend_helpers.js'
import { totalHoursForPeriodMapper } from '../../utils/server_method_helpers.js'

Expand Down Expand Up @@ -61,8 +62,8 @@ Template.periodtimetable.onRendered(() => {
.map((key) => key[1]))
}
const columns = [
{ name: t('globals.project'), editable: false },
{ name: t('globals.resource'), editable: false },
{ name: t('globals.project'), editable: false, format: addToolTipToTableCell },
{ name: t('globals.resource'), editable: false, format: addToolTipToTableCell },
{
name: getUserTimeUnitVerbose(),
editable: false,
Expand Down
3 changes: 2 additions & 1 deletion imports/ui/components/projectAccessRights.js
Expand Up @@ -2,7 +2,7 @@ import { FlowRouter } from 'meteor/ostrio:flow-router-extra'
import './projectAccessRights.html'
import { t, i18nReady } from '../../utils/i18n.js'
import {
validateEmail, getGlobalSetting, showToast,
validateEmail, getGlobalSetting, showToast, addToolTipToTableCell,
} from '../../utils/frontend_helpers'
import Projects from '../../api/projects/projects.js'

Expand All @@ -28,6 +28,7 @@ Template.projectAccessRights.onRendered(() => {
name: t('globals.name'),
editable: false,
focusable: false,
format: addToolTipToTableCell,
}, {
name: t('project.access_rights'),
editable: false,
Expand Down
2 changes: 1 addition & 1 deletion imports/ui/components/projectchart.js
Expand Up @@ -200,7 +200,7 @@ Template.projectchart.onRendered(() => {
colors: [Projects.findOne({ _id: templateInstance.data.projectId }).color || '#009688', '#66c0b8', '#e4e4e4'],
height: 230,
data: {
labels: templateInstance.topTasks.get().map((task) => task._id),
labels: templateInstance.topTasks.get().map((task) => $('<span>').text(task._id).html()),
datasets: [{
values: templateInstance.topTasks.get().map((task) => task.count),
}],
Expand Down
3 changes: 2 additions & 1 deletion imports/ui/pages/dashboard.js
Expand Up @@ -10,6 +10,7 @@ import {
getGlobalSetting,
timeInUserUnit,
getUserTimeUnitVerbose,
addToolTipToTableCell,
} from '../../utils/frontend_helpers'
import './dashboard.html'
import Timecards from '../../api/timecards/timecards'
Expand Down Expand Up @@ -126,7 +127,7 @@ Template.dashboard.onRendered(() => {
const precision = getUserSetting('precision')
for (const timecard of Timecards.find({}, { sort: { date: 1 } }).fetch()) {
taskmap.set(
timecard.task.replace(/(:\S*:)/g, emojify),
$('<span>').text(timecard.task.replace(/(:\S*:)/g, emojify)).html(),
taskmap.get(timecard.task.replace(/(:\S*:)/g, emojify))
? Number(Number(taskmap.get(timecard.task.replace(/(:\S*:)/g, emojify))) + Number(timeInUnitHelper(timecard.hours)))
: Number(timeInUnitHelper(timecard.hours)),
Expand Down
3 changes: 2 additions & 1 deletion imports/utils/frontend_helpers.js
Expand Up @@ -18,7 +18,8 @@ function getUserSetting(field) {

function addToolTipToTableCell(value) {
if (value) {
return `<span class="js-tooltip" data-bs-toggle="tooltip" data-bs-placement="left" title="${value}">${value}</span>`
const sanitizedValue = $('<div/>').text(value).html()
return `<span class="js-tooltip" data-bs-toggle="tooltip" data-bs-placement="left" title='${sanitizedValue}'>${sanitizedValue}</span>`
}
return ''
}
Expand Down
3 changes: 2 additions & 1 deletion imports/utils/server_method_helpers.js
Expand Up @@ -67,7 +67,8 @@ function totalHoursForPeriodMapper(entry) {
}
return {
projectId: Projects.findOne({ _id: entry._id.projectId }).name,
userId: projectUsers.findOne().users.find((elem) => elem._id === entry._id.userId)?.profile?.name,
userId: projectUsers
.findOne().users.find((elem) => elem._id === entry._id.userId)?.profile?.name,
totalHours,
}
}
Expand Down
24 changes: 12 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "titra",
"version": "0.76.1",
"version": "0.77.0",
"private": true,
"scripts": {
"start": "meteor run"
Expand All @@ -19,7 +19,7 @@
"bootstrap": "^5.1.3",
"content-type": "^1.0.4",
"date-holidays": "^3.16.0",
"dayjs": "^1.11.2",
"dayjs": "^1.11.3",
"dayjs-precise-range": "^1.0.1",
"docker-names": "^1.2.1",
"file-saver": "^2.0.5",
Expand All @@ -46,7 +46,7 @@
"devDependencies": {
"@babel/core": "^7.18.2",
"@babel/eslint-parser": "^7.18.2",
"eslint": "^8.16.0",
"eslint": "^8.17.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-import-resolver-meteor": "^0.4.0",
"eslint-plugin-i18next": "^5.2.1",
Expand Down

0 comments on commit e606b67

Please sign in to comment.