fix(custom-templates): XSS issue in Custom Template Note <EE-1054> (#5766)

fix(custom-templates): XSS issue in Custom Template Note <EE-1054> (#5766)
pull/5789/head
Marcelo Rydel 2021-09-29 16:47:39 -03:00 committed by GitHub
parent fe8f50512c
commit fce885901f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 8 deletions

View File

@ -3,6 +3,7 @@ package customtemplates
import (
"errors"
"net/http"
"regexp"
"strconv"
"github.com/asaskevich/govalidator"
@ -129,9 +130,20 @@ func (payload *customTemplateFromFileContentPayload) Validate(r *http.Request) e
if payload.Type != portainer.KubernetesStack && payload.Type != portainer.DockerSwarmStack && payload.Type != portainer.DockerComposeStack {
return errors.New("Invalid custom template type")
}
if !isValidNote(payload.Note) {
return errors.New("Invalid note. <img> tag is not supported")
}
return nil
}
func isValidNote(note string) bool {
if govalidator.IsNull(note) {
return true
}
match, _ := regexp.MatchString("<img", note)
return !match
}
func (handler *Handler) createCustomTemplateFromFileContent(r *http.Request) (*portainer.CustomTemplate, error) {
var payload customTemplateFromFileContentPayload
err := request.DecodeAndValidateJSONPayload(r, &payload)
@ -218,6 +230,9 @@ func (payload *customTemplateFromGitRepositoryPayload) Validate(r *http.Request)
if payload.Type != portainer.DockerSwarmStack && payload.Type != portainer.DockerComposeStack {
return errors.New("Invalid custom template type")
}
if !isValidNote(payload.Note) {
return errors.New("Invalid note. <img> tag is not supported")
}
return nil
}
@ -285,6 +300,9 @@ func (payload *customTemplateFromFileUploadPayload) Validate(r *http.Request) er
payload.Logo = logo
note, _ := request.RetrieveMultiPartFormValue(r, "Note", true)
if !isValidNote(note) {
return errors.New("Invalid note. <img> tag is not supported")
}
payload.Note = note
typeNumeral, _ := request.RetrieveNumericMultiPartFormValue(r, "Type", true)

View File

@ -51,6 +51,9 @@ func (payload *customTemplateUpdatePayload) Validate(r *http.Request) error {
if govalidator.IsNull(payload.Description) {
return errors.New("Invalid custom template description")
}
if !isValidNote(payload.Note) {
return errors.New("Invalid note. <img> tag is not supported")
}
return nil
}

View File

@ -1,4 +1,6 @@
import _ from 'lodash-es';
export function TagViewModel(data) {
this.Id = data.ID;
this.Name = data.Name;
this.Name = _.escape(data.Name);
}

View File

@ -1,5 +1,7 @@
import _ from 'lodash-es';
export function TeamViewModel(data) {
this.Id = data.Id;
this.Name = data.Name;
this.Name = _.escape(data.Name);
this.Checked = false;
}

View File

@ -3,15 +3,21 @@ import angular from 'angular';
angular.module('portainer.app').factory('CustomTemplateService', CustomTemplateServiceFactory);
/* @ngInject */
function CustomTemplateServiceFactory(CustomTemplates, FileUploadService) {
function CustomTemplateServiceFactory($sanitize, CustomTemplates, FileUploadService) {
var service = {};
service.customTemplate = function customTemplate(id) {
return CustomTemplates.get({ id }).$promise;
};
service.customTemplates = function customTemplates(type) {
return CustomTemplates.query({ type }).$promise;
service.customTemplates = async function customTemplates(type) {
const templates = await CustomTemplates.query({ type }).$promise;
templates.forEach((template) => {
if (template.Note) {
template.Note = $('<p>').html($sanitize(template.Note)).find('img').remove().end().html();
}
});
return templates;
};
service.remove = function remove(id) {

View File

@ -1,3 +1,4 @@
import _ from 'lodash-es';
import toastr from 'toastr';
angular.module('portainer.app').factory('Notifications', [
@ -7,11 +8,11 @@ angular.module('portainer.app').factory('Notifications', [
var service = {};
service.success = function (title, text) {
toastr.success($sanitize(text), $sanitize(title));
toastr.success($sanitize(_.escape(text)), $sanitize(title));
};
service.warning = function (title, text) {
toastr.warning($sanitize(text), $sanitize(title), { timeOut: 6000 });
toastr.warning($sanitize(_.escape(text)), $sanitize(title), { timeOut: 6000 });
};
service.error = function (title, e, fallbackText) {
@ -44,7 +45,7 @@ angular.module('portainer.app').factory('Notifications', [
console.error(e);
if (msg !== 'Invalid JWT token') {
toastr.error($sanitize(msg), $sanitize(title), { timeOut: 6000 });
toastr.error($sanitize(_.escape(msg)), $sanitize(title), { timeOut: 6000 });
}
};