internal/report: add lint check for markdown formatting

Add lint check for common Markdown-style formatting elements
that should not be in our reports, such as backticks, headings,
and structured links.

Change-Id: Id9676492008b4f6e590d5bdae235228cc397fed8
Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/549238
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/genericosv/testdata/yaml/GHSA-33m6-q9v5-62r7.yaml b/internal/genericosv/testdata/yaml/GHSA-33m6-q9v5-62r7.yaml
index 6d94d0b..c694867 100644
--- a/internal/genericosv/testdata/yaml/GHSA-33m6-q9v5-62r7.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-33m6-q9v5-62r7.yaml
@@ -55,6 +55,8 @@
     - web: https://bugzilla.redhat.com/show_bug.cgi?id=1954376
     - web: https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMSATORIGOUUID-72488
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found `github.com/satori/go.uuid`)'
     - lint: 'modules[0] "github.com/apptainer/sif": 2 versions do not exist: 1.2.1-0.20180103161547-0ef6afb2f6cd, 1.2.1-0.20180404165556-75cca531ea76'
     - lint: 'modules[1] "github.com/satori/go.uuid": vulnerable_at: 1.2.0 is not inside vulnerable range'
     - lint: 'references: too many advisories (found 2, want <=1)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-5m6c-jp6f-2vcv.yaml b/internal/genericosv/testdata/yaml/GHSA-5m6c-jp6f-2vcv.yaml
index 28b211c..f203c19 100644
--- a/internal/genericosv/testdata/yaml/GHSA-5m6c-jp6f-2vcv.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-5m6c-jp6f-2vcv.yaml
@@ -21,6 +21,7 @@
     - fix: https://github.com/oauth2-proxy/oauth2-proxy/commit/ee5662e0f5001d76ec76562bb605abbd07c266a2
     - web: https://github.com/oauth2-proxy/oauth2-proxy/releases/tag/v6.0.0
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
     - lint: 'modules[0] "github.com/oauth2-proxy/oauth2-proxy": 2 versions do not exist: 5.1.1, 6.0.0'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/oauth2-proxy/oauth2-proxy")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-627p-rr78-99rj.yaml b/internal/genericosv/testdata/yaml/GHSA-627p-rr78-99rj.yaml
index 671a9e9..f2216ae 100644
--- a/internal/genericosv/testdata/yaml/GHSA-627p-rr78-99rj.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-627p-rr78-99rj.yaml
@@ -66,6 +66,9 @@
     - advisory: https://nvd.nist.gov/vuln/detail/CVE-2020-5415
     - web: https://tanzu.vmware.com/security/cve-2020-5415
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [GitLab auth docs](https://concourse-ci.org/gitlab-auth.html))'
+    - lint: 'description: possible markdown formatting (found `users`)'
     - lint: 'modules[0] "github.com/concourse/concourse": 4 versions do not exist: 6.3.0, 6.3.1, 6.4.0, 6.4.1'
     - lint: 'modules[1] "github.com/concourse/dex": 4 versions do not exist: 6.3.0, 6.3.1, 6.4.0, 6.4.1'
     - lint: 'references: too many advisories (found 2, want <=1)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-66p8-j459-rq63.yaml b/internal/genericosv/testdata/yaml/GHSA-66p8-j459-rq63.yaml
index 5791009..2be42cd 100644
--- a/internal/genericosv/testdata/yaml/GHSA-66p8-j459-rq63.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-66p8-j459-rq63.yaml
@@ -43,6 +43,9 @@
     - advisory: https://nvd.nist.gov/vuln/detail/CVE-2023-25168
     - fix: https://github.com/pterodactyl/wings/commit/429ac62dba22997a278bc709df5ac00a5a25d83d
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [`GHSA-p8r3-83r8-jwj5`](https://github.com/pterodactyl/wings/security/advisories/GHSA-p8r3-83r8-jwj5))'
+    - lint: 'description: possible markdown formatting (found `GHSA-p8r3-83r8-jwj5`)'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/pterodactyl/wings")'
     - lint: 'summary: too long (found 131 characters, want <=100)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-69v6-xc2j-r2jf.yaml b/internal/genericosv/testdata/yaml/GHSA-69v6-xc2j-r2jf.yaml
index 9df2fb2..dbe0e0c 100644
--- a/internal/genericosv/testdata/yaml/GHSA-69v6-xc2j-r2jf.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-69v6-xc2j-r2jf.yaml
@@ -40,6 +40,9 @@
     - fix: https://github.com/ethereum/go-ethereum/commit/295693759e5ded05fec0b2fb39359965b60da785
     - web: https://blog.ethereum.org/2020/11/12/geth_security_release/
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [go-ethereum](https://github.com/ethereum/go-ethereum))'
+    - lint: 'description: possible markdown formatting (found `dataCopy` (at `0x00...04`)'
     - lint: 'modules[1] "github.com/ethereum/go-ethereum": packages[0] "github.com/ethereum/go-ethereum/core/vm": at least one of vulnerable_at and skip_fix must be set'
     - lint: 'modules[1] "github.com/ethereum/go-ethereum": version 1.19.7 does not exist'
     - lint: 'references: too many advisories (found 2, want <=1)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-6rg3-8h8x-5xfv.yaml b/internal/genericosv/testdata/yaml/GHSA-6rg3-8h8x-5xfv.yaml
index f3b2f7b..446b239 100644
--- a/internal/genericosv/testdata/yaml/GHSA-6rg3-8h8x-5xfv.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-6rg3-8h8x-5xfv.yaml
@@ -28,5 +28,6 @@
 references:
     - advisory: https://github.com/pterodactyl/wings/security/advisories/GHSA-6rg3-8h8x-5xfv
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/pterodactyl/wings")'
     - lint: 'summary: too long (found 110 characters, want <=100)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-7943-82jg-wmw5.yaml b/internal/genericosv/testdata/yaml/GHSA-7943-82jg-wmw5.yaml
index 3596a12..8bd5f6b 100644
--- a/internal/genericosv/testdata/yaml/GHSA-7943-82jg-wmw5.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-7943-82jg-wmw5.yaml
@@ -128,6 +128,9 @@
     - web: https://github.com/argoproj/argo-cd/releases/tag/v2.3.6
     - web: https://github.com/argoproj/argo-cd/releases/tag/v2.4.5
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [discussions](https://github.com/argoproj/argo-cd/discussions))'
+    - lint: 'description: possible markdown formatting (found `--dex-server`)'
     - lint: 'modules[0] "github.com/argoproj/argo-cd": version 2.2.11 does not exist'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/argoproj/argo-cd")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-cf7g-cm7q-rq7f.yaml b/internal/genericosv/testdata/yaml/GHSA-cf7g-cm7q-rq7f.yaml
index d3e9818..2aa3473 100644
--- a/internal/genericosv/testdata/yaml/GHSA-cf7g-cm7q-rq7f.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-cf7g-cm7q-rq7f.yaml
@@ -19,6 +19,7 @@
     - advisory: https://nvd.nist.gov/vuln/detail/CVE-2022-39220
     - fix: https://github.com/drakkan/sftpgo/commit/cbef217cfa92478ee8e00ba1a5fb074f8a8aeee0
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
     - lint: 'modules[0] "github.com/drakkan/sftpgo": version 2.3.5 does not exist'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/drakkan/sftpgo")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-fv82-r8qv-ch4v.yaml b/internal/genericosv/testdata/yaml/GHSA-fv82-r8qv-ch4v.yaml
index 884aa26..a6909bf 100644
--- a/internal/genericosv/testdata/yaml/GHSA-fv82-r8qv-ch4v.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-fv82-r8qv-ch4v.yaml
@@ -36,5 +36,7 @@
     - advisory: https://nvd.nist.gov/vuln/detail/CVE-2021-29652
     - fix: https://github.com/pomerium/pomerium/pull/2048
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [pomerium](http://github.com/pomerium/pomerium))'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must begin with a capital letter'
diff --git a/internal/genericosv/testdata/yaml/GHSA-g5gj-9ggf-9vmq.yaml b/internal/genericosv/testdata/yaml/GHSA-g5gj-9ggf-9vmq.yaml
index a7d87d3..c3175e8 100644
--- a/internal/genericosv/testdata/yaml/GHSA-g5gj-9ggf-9vmq.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-g5gj-9ggf-9vmq.yaml
@@ -25,5 +25,6 @@
     - web: https://github.com/cloudflare/cfrpki/releases/tag/v1.4.0
     - web: https://www.debian.org/security/2022/dsa-5041
 notes:
+    - lint: 'description: possible markdown formatting (found ## )'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/cloudflare/cfrpki")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-g9wh-3vrx-r7hg.yaml b/internal/genericosv/testdata/yaml/GHSA-g9wh-3vrx-r7hg.yaml
index c5bb973..168f628 100644
--- a/internal/genericosv/testdata/yaml/GHSA-g9wh-3vrx-r7hg.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-g9wh-3vrx-r7hg.yaml
@@ -24,5 +24,6 @@
     - fix: https://github.com/cloudflare/cfrpki/commit/648658b1b176a747b52645989cfddc73a81eacad
     - web: https://www.debian.org/security/2022/dsa-5041
 notes:
+    - lint: 'description: possible markdown formatting (found ## )'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/cloudflare/cfrpki")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-hmfx-3pcx-653p.yaml b/internal/genericosv/testdata/yaml/GHSA-hmfx-3pcx-653p.yaml
index 134d54f..172b178 100644
--- a/internal/genericosv/testdata/yaml/GHSA-hmfx-3pcx-653p.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-hmfx-3pcx-653p.yaml
@@ -71,4 +71,7 @@
     - web: https://github.com/containerd/containerd/releases/tag/v1.6.18
     - web: https://www.benthamsgaze.org/2022/08/22/vulnerability-in-linux-containers-investigation-and-mitigation/
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [containerd](https://github.com/containerd/containerd/issues/new/choose))'
+    - lint: 'description: possible markdown formatting (found `"USER $USERNAME"`)'
     - lint: 'references: too many advisories (found 5, want <=1)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-hv53-vf5m-8q94.yaml b/internal/genericosv/testdata/yaml/GHSA-hv53-vf5m-8q94.yaml
index 79d9767..0c505ed 100644
--- a/internal/genericosv/testdata/yaml/GHSA-hv53-vf5m-8q94.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-hv53-vf5m-8q94.yaml
@@ -53,6 +53,8 @@
     - advisory: https://github.com/personnummer/go/security/advisories/GHSA-hv53-vf5m-8q94
     - web: https://pkg.go.dev/github.com/personnummer/go
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [C#](https://github.com/advisories/GHSA-qv8q-v995-72gr))'
     - lint: 'modules[0] "github.com/personnummer/go": version 3.0.1 does not exist'
     - lint: 'summary: must begin with a capital letter'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/personnummer/go")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-jmp2-wc4p-wfh2.yaml b/internal/genericosv/testdata/yaml/GHSA-jmp2-wc4p-wfh2.yaml
index 397c72b..953c738 100644
--- a/internal/genericosv/testdata/yaml/GHSA-jmp2-wc4p-wfh2.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-jmp2-wc4p-wfh2.yaml
@@ -59,6 +59,9 @@
     - web: https://github.com/mutagen-io/mutagen/releases/tag/v0.16.6
     - web: https://github.com/mutagen-io/mutagen/releases/tag/v0.17.1
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [CVE-2003-0069](https://nvd.nist.gov/vuln/detail/CVE-2003-0069))'
+    - lint: 'description: possible markdown formatting (found `list`)'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/mutagen-io/mutagen")'
     - lint: 'summary: too long (found 111 characters, want <=100)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-pg5p-wwp8-97g8.yaml b/internal/genericosv/testdata/yaml/GHSA-pg5p-wwp8-97g8.yaml
index f221579..99172bf 100644
--- a/internal/genericosv/testdata/yaml/GHSA-pg5p-wwp8-97g8.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-pg5p-wwp8-97g8.yaml
@@ -61,6 +61,8 @@
     - advisory: https://github.com/cilium/cilium/security/advisories/GHSA-pg5p-wwp8-97g8
     - advisory: https://nvd.nist.gov/vuln/detail/CVE-2023-29002
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [Slack](https://docs.cilium.io/en/latest/community/community/#slack))'
     - lint: 'modules[0] "github.com/cilium/cilium": unsupported_versions: found 1 (want none)'
     - lint: 'modules[0] "github.com/cilium/cilium": versions: introduced and fixed versions must alternate'
     - lint: 'references: too many advisories (found 2, want <=1)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-pmfr-63c2-jr5c.yaml b/internal/genericosv/testdata/yaml/GHSA-pmfr-63c2-jr5c.yaml
index 0cac627..078068e 100644
--- a/internal/genericosv/testdata/yaml/GHSA-pmfr-63c2-jr5c.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-pmfr-63c2-jr5c.yaml
@@ -68,6 +68,9 @@
     - web: http://lists.opensuse.org/opensuse-security-announce/2020-07/msg00059.html
     - web: http://lists.opensuse.org/opensuse-security-announce/2020-09/msg00053.html
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [Singularity Slack Channel](https://bit.ly/2m0g3lX))'
+    - lint: 'description: possible markdown formatting (found `legacyinsecure`)'
     - lint: 'modules[0] "github.com/sylabs/singularity": version 3.6.0 does not exist'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/sylabs/singularity")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-vp35-85q5-9f25.yaml b/internal/genericosv/testdata/yaml/GHSA-vp35-85q5-9f25.yaml
index c493d91..84c56a2 100644
--- a/internal/genericosv/testdata/yaml/GHSA-vp35-85q5-9f25.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-vp35-85q5-9f25.yaml
@@ -109,4 +109,7 @@
     - web: https://github.com/moby/moby/releases/tag/v20.10.20
     - web: https://lore.kernel.org/git/xmqq4jw1uku5.fsf@gitster.g/T/#u
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [Open an issue](https://github.com/moby/moby/issues/new))'
+    - lint: 'description: possible markdown formatting (found `git+<protocol>://...`)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/moby/moby")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-w4xh-w33p-4v29.yaml b/internal/genericosv/testdata/yaml/GHSA-w4xh-w33p-4v29.yaml
index 95901af..0938489 100644
--- a/internal/genericosv/testdata/yaml/GHSA-w4xh-w33p-4v29.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-w4xh-w33p-4v29.yaml
@@ -28,6 +28,7 @@
     - web: http://blog.recurity-labs.com/2017-08-10/scm-vulns
     - web: http://www.securityfocus.com/bid/102926
 notes:
+    - lint: 'description: possible markdown formatting (found `url =` line in a `.lfsconfig`)'
     - lint: 'modules[0] "github.com/git-lfs/git-lfs": version 2.1.1-0.20170519163204-f913f5f9c7c6 does not exist'
     - lint: 'modules[1] "github.com/git-lfs/git-lfs": packages[0] "github.com/git-lfs/git-lfs/lfsapi": at least one of vulnerable_at and skip_fix must be set'
     - lint: 'modules[1] "github.com/git-lfs/git-lfs": version 2.1.1-0.20170519163204-f913f5f9c7c6 does not exist'
diff --git a/internal/genericosv/testdata/yaml/GHSA-wx8q-rgfr-cf6v.yaml b/internal/genericosv/testdata/yaml/GHSA-wx8q-rgfr-cf6v.yaml
index 2f05d22..53fa91f 100644
--- a/internal/genericosv/testdata/yaml/GHSA-wx8q-rgfr-cf6v.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-wx8q-rgfr-cf6v.yaml
@@ -28,5 +28,6 @@
     - advisory: https://nvd.nist.gov/vuln/detail/CVE-2021-22565
     - web: https://github.com/google/exposure-notifications-verification-server/releases/tag/v1.1.2
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: too long (found 106 characters, want <=100)'
diff --git a/internal/genericosv/testdata/yaml/GHSA-xmg8-99r8-jc2j.yaml b/internal/genericosv/testdata/yaml/GHSA-xmg8-99r8-jc2j.yaml
index aa31e84..2fb478e 100644
--- a/internal/genericosv/testdata/yaml/GHSA-xmg8-99r8-jc2j.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-xmg8-99r8-jc2j.yaml
@@ -72,6 +72,8 @@
     - web: https://github.com/argoproj/argo-cd/releases/tag/v2.2.9
     - web: https://github.com/argoproj/argo-cd/releases/tag/v2.3.4
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
+    - lint: 'description: possible markdown formatting (found [discussions](https://github.com/argoproj/argo-cd/discussions))'
     - lint: 'modules[0] "github.com/argoproj/argo-cd": version 2.1.15 does not exist'
     - lint: 'references: too many advisories (found 2, want <=1)'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/argoproj/argo-cd")'
diff --git a/internal/genericosv/testdata/yaml/GHSA-xx9w-464f-7h6f.yaml b/internal/genericosv/testdata/yaml/GHSA-xx9w-464f-7h6f.yaml
index d1fd09b..a025550 100644
--- a/internal/genericosv/testdata/yaml/GHSA-xx9w-464f-7h6f.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-xx9w-464f-7h6f.yaml
@@ -42,5 +42,6 @@
 references:
     - advisory: https://github.com/goharbor/harbor/security/advisories/GHSA-xx9w-464f-7h6f
 notes:
+    - lint: 'description: possible markdown formatting (found ### )'
     - lint: 'modules[0] "github.com/goharbor/harbor": version 1.0.0 does not exist'
     - lint: 'summary: must contain an affected module or package path (e.g. "github.com/goharbor/harbor")'
diff --git a/internal/report/lint.go b/internal/report/lint.go
index c585b5f..22fd444 100644
--- a/internal/report/lint.go
+++ b/internal/report/lint.go
@@ -267,6 +267,7 @@
 func (d *Description) lint(l *linter, r *Report) {
 	desc := d.String()
 
+	checkNoMarkdown(l, desc)
 	r.lintLineLength(l, desc)
 	if !r.IsExcluded() && desc == "" {
 		if r.CVEMetadata != nil {
@@ -289,6 +290,7 @@
 		// No need to keep linting, as this is likely a placeholder value.
 		return
 	}
+	checkNoMarkdown(l, summary)
 	if ln := len(summary); ln > 100 {
 		l.Errorf("too long (found %d characters, want <=100)", ln)
 	}
@@ -569,3 +571,20 @@
 func hasTODO(s string) bool {
 	return strings.Contains(s, "TODO")
 }
+
+// Regular expressions for markdown-style elements that shouldn't
+// be in our descriptions/summaries.
+var (
+	backtickRE = regexp.MustCompile("(`.*`)")
+	linkRE     = regexp.MustCompile(`(\[.*\]\(.*\))`)
+	headingRE  = regexp.MustCompile(`(#+ )`)
+)
+
+func checkNoMarkdown(l *linter, s string) {
+	for _, re := range []*regexp.Regexp{backtickRE, linkRE, headingRE} {
+		matches := re.FindStringSubmatch(s)
+		if len(matches) > 0 {
+			l.Errorf("possible markdown formatting (found %s)", matches[1])
+		}
+	}
+}
diff --git a/internal/report/lint_test.go b/internal/report/lint_test.go
index c6aee64..3af92bc 100644
--- a/internal/report/lint_test.go
+++ b/internal/report/lint_test.go
@@ -675,6 +675,17 @@
 			report: validExcludedReport(noop),
 			// No lints.
 		},
+		{
+			name: "markdown",
+			desc: "Descriptions and summaries should not contain Markdown formatting.",
+			report: validReport(
+				func(r *Report) {
+					r.Summary += " in function `Hello`"
+					r.Description = "# Problem\nMore info [here](https://example.com)"
+				},
+			),
+			wantNumLints: 3,
+		},
 	} {
 		test := test
 		t.Run(test.name, func(t *testing.T) {
diff --git a/internal/report/testdata/lint/TestLintOffline/markdown.txtar b/internal/report/testdata/lint/TestLintOffline/markdown.txtar
new file mode 100644
index 0000000..64a4e18
--- /dev/null
+++ b/internal/report/testdata/lint/TestLintOffline/markdown.txtar
@@ -0,0 +1,25 @@
+Copyright 2023 The Go Authors. All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+
+Test: TestLintOffline/markdown
+Description: Descriptions and summaries should not contain Markdown formatting.
+
+-- data/reports/GO-0000-0000.yaml --
+id: GO-0000-0000
+modules:
+    - module: golang.org/x/net
+      vulnerable_at: 1.2.3
+      packages:
+        - package: golang.org/x/net/http2
+summary: A summary of the issue in golang.org/x/net in function `Hello`
+description: |-
+    # Problem
+    More info [here](https://example.com)
+cves:
+    - CVE-1234-0000
+
+-- golden --
+summary: possible markdown formatting (found `Hello`)
+description: possible markdown formatting (found [here](https://example.com))
+description: possible markdown formatting (found # )