mirror of https://github.com/portainer/portainer
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
parent
fe8f50512c
commit
fce885901f
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue