diff --git a/modules/markup/markdown/meta.go b/modules/markup/markdown/meta.go
index ca95e4d26a..faf92ae2c6 100644
--- a/modules/markup/markdown/meta.go
+++ b/modules/markup/markdown/meta.go
@@ -25,20 +25,22 @@ func isYAMLSeparator(line string) bool {
 // and returns the frontmatter metadata separated from the markdown content
 func ExtractMetadata(contents string, out interface{}) (string, error) {
 	var front, body []string
-	var seps int
 	lines := strings.Split(contents, "\n")
 	for idx, line := range lines {
-		if seps == 2 {
-			front, body = lines[:idx], lines[idx:]
-			break
+		if idx == 0 {
+			// First line has to be a separator
+			if !isYAMLSeparator(line) {
+				return "", errors.New("frontmatter must start with a separator line")
+			}
+			continue
 		}
 		if isYAMLSeparator(line) {
-			seps++
-			continue
+			front, body = lines[1:idx], lines[idx+1:]
+			break
 		}
 	}
 
-	if len(front) == 0 && len(body) == 0 {
+	if len(front) == 0 {
 		return "", errors.New("could not determine metadata")
 	}
 
diff --git a/modules/markup/markdown/meta_test.go b/modules/markup/markdown/meta_test.go
new file mode 100644
index 0000000000..a585f0382f
--- /dev/null
+++ b/modules/markup/markdown/meta_test.go
@@ -0,0 +1,63 @@
+// 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 markdown
+
+import (
+	"fmt"
+	"testing"
+
+	"code.gitea.io/gitea/modules/structs"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestExtractMetadata(t *testing.T) {
+	t.Run("ValidFrontAndBody", func(t *testing.T) {
+		var meta structs.IssueTemplate
+		body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta)
+		assert.NoError(t, err)
+		assert.Equal(t, body, bodyTest)
+		assert.Equal(t, metaTest, meta)
+		assert.True(t, meta.Valid())
+	})
+
+	t.Run("NoFirstSeparator", func(t *testing.T) {
+		var meta structs.IssueTemplate
+		_, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta)
+		assert.Error(t, err)
+	})
+
+	t.Run("NoLastSeparator", func(t *testing.T) {
+		var meta structs.IssueTemplate
+		_, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta)
+		assert.Error(t, err)
+	})
+
+	t.Run("NoBody", func(t *testing.T) {
+		var meta structs.IssueTemplate
+		body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest), &meta)
+		assert.NoError(t, err)
+		assert.Equal(t, body, "")
+		assert.Equal(t, metaTest, meta)
+		assert.True(t, meta.Valid())
+	})
+}
+
+var (
+	sepTest   = "-----"
+	frontTest = `name: Test
+about: "A Test"
+title: "Test Title"
+labels:
+  - bug
+  - "test label"`
+	bodyTest = "This is the body"
+	metaTest = structs.IssueTemplate{
+		Name:   "Test",
+		About:  "A Test",
+		Title:  "Test Title",
+		Labels: []string{"bug", "test label"},
+	}
+)