diff --git a/modules/image/svg.go b/modules/image/svg.go
new file mode 100644
index 0000000000000..b26fe04b45fd4
--- /dev/null
+++ b/modules/image/svg.go
@@ -0,0 +1,46 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+ "io"
+ "regexp"
+ "strings"
+
+ "github.com/microcosm-cc/bluemonday"
+)
+
+// SanitizeSVG remove potential malicious dom elements
+func SanitizeSVG(svgData io.Reader) string {
+ //TODO init policy at start-up and keep it
+ p := bluemonday.NewPolicy()
+ p.AllowElements("svg", "title", "path", "desc", "g", "a", "line")
+ p.AllowNoAttrs().OnElements("svg", "title", "desc", "g", "a")
+ p.AllowAttrs("id", "viewBox", "role", "aria-labelledby", "xmlns", "xmlns:xlink", "xml:space").OnElements("svg")
+ p.AllowAttrs("version").Matching(regexp.MustCompile(`^\d+(\.\d+)?$`)).OnElements("svg")
+ p.AllowAttrs("id").OnElements("title", "desc")
+ p.AllowAttrs("id", "data-name", "class", "aria-label").OnElements("g")
+ p.AllowAttrs("id", "data-name", "class", "d", "transform", "aria-haspopup").OnElements("path")
+ p.AllowAttrs("x", "y", "width", "height").OnElements("rect", "svg")
+ p.AllowAttrs("x1", "y1", "x2", "y2").Matching(regexp.MustCompile(`^\d+(\.\d+)?$`)).OnElements("line")
+ p.AllowAttrs("stroke-miterlimit").Matching(regexp.MustCompile(`^\d+$`)).OnElements("line")
+ p.AllowAttrs("stroke", "fill").Matching(regexp.MustCompile(`^(#\d+)|(\w+)$`)).OnElements("line", "rect")
+ p.AllowAttrs("href", "xlink:href").Matching(regexp.MustCompile(`^#\w+$`)).OnElements("a")
+
+ //TODO find a good way to allow relative url import
+ //var invalidID = regexp.MustCompile(`((http|ftp)s?)|(url *\( *' *//)`)
+ //var validID = regexp.MustCompile(`(?!((http|ftp)s?)|(url *\( *' *//))`) //not supported
+ //p.AllowAttrs("fill").Matching(regexp.MustCompile(`^(\w+)|(url\(#\w+\))$`)).OnElements("rect")
+
+ p.SkipElementsContent("this", "script")
+ cleanedSVG := p.SanitizeReader(svgData).String()
+
+ //Remove empty lines
+ cleanedSVG = strings.TrimSpace(cleanedSVG)
+ r := regexp.MustCompile("\n+") //TODO move this somewhere else
+ cleanedSVG = r.ReplaceAllString(cleanedSVG, "\n")
+
+ return cleanedSVG
+}
diff --git a/modules/image/svg_test.go b/modules/image/svg_test.go
new file mode 100644
index 0000000000000..29c6b2bcf8058
--- /dev/null
+++ b/modules/image/svg_test.go
@@ -0,0 +1,345 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSanitizeSVG(t *testing.T) {
+ tests := []struct {
+ name string
+ input string
+ want string
+ }{
+ {
+ name: "ariaData",
+ input: ``,
+ /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base
+ Diff:
+ --- Expected
+ +++ Actual
+ @@ -1,2 +1,2 @@
+ -