diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go
index 45d363b37e..0ebb3ff88b 100644
--- a/modules/markup/sanitizer.go
+++ b/modules/markup/sanitizer.go
@@ -47,6 +47,9 @@ func ReplaceSanitizer() {
 
 	// Allow keyword markup
 	sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span")
+
+	// Allow <kbd> tags for keyboard shortcut styling
+	sanitizer.policy.AllowElements("kbd")
 }
 
 // Sanitize takes a string that contains a HTML fragment or document and applies policy whitelist.
diff --git a/modules/markup/sanitizer_test.go b/modules/markup/sanitizer_test.go
index 211201d201..be7bdd20e7 100644
--- a/modules/markup/sanitizer_test.go
+++ b/modules/markup/sanitizer_test.go
@@ -35,6 +35,9 @@ func Test_Sanitizer(t *testing.T) {
 <code class="language-lol&#32;ui&#32;container&#32;input&#32;massive&#32;basic&#32;segment">Hello there! Something has gone wrong, we are working on it.</code>
 <code class="language-lol&#32;ui&#32;container&#32;input&#32;huge&#32;basic&#32;segment">In the meantime, play a game with us at&nbsp;<a href="http://example.com/">example.com</a>.</code>
 </code>`, "<code>\n<code>\u00a0</code>\n<img src=\"https://try.gogs.io/img/favicon.png\" width=\"200\" height=\"200\">\n<code>Hello there! Something has gone wrong, we are working on it.</code>\n<code>In the meantime, play a game with us at\u00a0<a href=\"http://example.com/\" rel=\"nofollow\">example.com</a>.</code>\n</code>",
+
+		// <kbd> tags
+		`<kbd>Ctrl + C</kbd>`, `<kbd>Ctrl + C</kbd>`,
 	}
 
 	for i := 0; i < len(testCases); i += 2 {