diff --git a/modules/markup/html.go b/modules/markup/html.go
index e28e26c6d1..df2a159230 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -55,7 +55,7 @@ var (
 	anySHA1Pattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`)
 
 	// comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash"
-	comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40})(\.\.\.?)([0-9a-f]{40})?(#[-+~_%.a-zA-Z0-9]+)?`)
+	comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,40})(\.\.\.?)([0-9a-f]{7,40})?(#[-+~_%.a-zA-Z0-9]+)?`)
 
 	validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
 
@@ -946,6 +946,13 @@ func comparePatternProcessor(ctx *RenderContext, node *html.Node) {
 			return
 		}
 
+		// Ensure that every group (m[0]...m[7]) has a match
+		for i := 0; i < 8; i++ {
+			if m[i] == -1 {
+				return
+			}
+		}
+
 		urlFull := node.Data[m[0]:m[1]]
 		text1 := base.ShortSha(node.Data[m[2]:m[3]])
 		textDots := base.ShortSha(node.Data[m[4]:m[5]])
diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go
index ee9b17df2f..29bf6c8fcb 100644
--- a/modules/markup/html_test.go
+++ b/modules/markup/html_test.go
@@ -548,3 +548,16 @@ func TestFuzz(t *testing.T) {
 
 	assert.NoError(t, err)
 }
+
+func TestIssue18471(t *testing.T) {
+	data := `http://domain/org/repo/compare/783b039...da951ce`
+
+	var res strings.Builder
+	err := PostProcess(&RenderContext{
+		URLPrefix: "https://example.com",
+		Metas:     localMetas,
+	}, strings.NewReader(data), &res)
+
+	assert.NoError(t, err)
+	assert.Equal(t, res.String(), "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">783b039...da951ce</code></a>")
+}