diff --git a/lib/platform/github/index.js b/lib/platform/github/index.js
index f392f5cfba0a6de91f0d378600a95ee6cd32b5f7..4cd650173f4d8efe7ffc50835eddbf0798652f9c 100644
--- a/lib/platform/github/index.js
+++ b/lib/platform/github/index.js
@@ -1,6 +1,7 @@
 const is = require('@sindresorhus/is');
 const addrs = require('email-addresses');
 const delay = require('delay');
+const showdown = require('showdown');
 const URL = require('url');
 
 const get = require('./gh-got-wrapper');
@@ -8,6 +9,9 @@ const hostRules = require('../../util/host-rules');
 const Storage = require('./storage');
 const GitStorage = require('../git/storage');
 
+const converter = new showdown.Converter();
+converter.setFlavor('github');
+
 let config = {};
 
 module.exports = {
@@ -1294,9 +1298,13 @@ function getPrBody(input) {
     return input.substring(0, 60000);
   }
   return (
-    input
+    converter
+      .makeHtml(input)
       // to be safe, replace all github.com links with renovatebot redirector
-      .replace(/]\(https:\/\/github\.com\//g, '](https://renovatebot.com/gh/')
+      .replace(
+        /href="https?:\/\/github.com\//g,
+        'href="https://renovatebot.com/gh/'
+      )
       .substring(0, 60000)
   );
 }
diff --git a/lib/platform/gitlab/index.js b/lib/platform/gitlab/index.js
index e7d8c8ece663b7e549a5f200d8bf5999e2b5c130..63efaf6554db96480fbf7cbbf160358bb6b6a4c6 100644
--- a/lib/platform/gitlab/index.js
+++ b/lib/platform/gitlab/index.js
@@ -1,9 +1,13 @@
 const is = require('@sindresorhus/is');
 const addrs = require('email-addresses');
+const showdown = require('showdown');
 
 const get = require('./gl-got-wrapper');
 const hostRules = require('../../util/host-rules');
 
+const converter = new showdown.Converter();
+converter.setFlavor('github');
+
 let config = {};
 
 module.exports = {
@@ -723,7 +727,17 @@ async function mergePr(iid) {
 }
 
 function getPrBody(input) {
-  return input.replace(/Pull Request/g, 'Merge Request').replace(/PR/g, 'MR');
+  // Convert to HTML using GitHub-flavoured markdown as it is more feature-rich than GitLab's flavour
+  return converter
+    .makeHtml(input)
+    .replace(/Pull Request/g, 'Merge Request')
+    .replace(/PR/g, 'MR')
+    .replace(
+      `<p><details><br />\n<summary>Release Notes</summary></p>`,
+      '\n<details>\n\n<summary>Release Notes</summary>\n\n'
+    )
+    .replace('<p></details></p>', '\n</details>\n');
+  // TODO: set maximum length
 }
 
 // Generic File operations
diff --git a/lib/workers/pr/pr-body.js b/lib/workers/pr/pr-body.js
index a5d473c42fb1f60bca4164b9adc898be4ab4515d..ad164a4bcf5e6e7a670ead0b168f5198c8976ec2 100644
--- a/lib/workers/pr/pr-body.js
+++ b/lib/workers/pr/pr-body.js
@@ -194,11 +194,26 @@ async function getPrBody(config) {
     }
   }
   prBody = prBody.trim();
-  prBody = prBody.replace(/\n\n\n+/g, '\n\n');
 
   // Clean up double v's
   prBody = prBody.replace(/\bvv(\d)/g, 'v$1');
-  // Get platform-specific transformations
+
+  // Generic replacements/link-breakers
+
+  // Put a zero width space after every # followed by a digit
+  prBody = prBody.replace(/#(\d)/gi, '#&#8203;$1');
+  // Put a zero width space after every @ symbol to prevent unintended hyperlinking
+  prBody = prBody.replace(/@/g, '@&#8203;');
+  prBody = prBody.replace(/(`\[?@)&#8203;/g, '$1');
+  prBody = prBody.replace(/([a-z]@)&#8203;/gi, '$1');
+  prBody = prBody.replace(/([\s(])#(\d+)([)\s]?)/g, '$1#&#8203;$2$3');
+  // convert escaped backticks back to `
+  const backTickRe = /&#x60;([^/]*?)&#x60;/g;
+  prBody = prBody.replace(backTickRe, '`$1`');
+  prBody = prBody.replace(/`#&#8203;(\d+)`/g, '`#$1`');
+
+  prBody = prBody.replace(/\n\n\n+/g, '\n\n');
+
   prBody = platform.getPrBody(prBody);
   return prBody;
 }
diff --git a/package.json b/package.json
index a4650fa3251f01e507598448f7c7cfaba4588139..e9970644ff6def862eb0d47a4d831861d002b0f0 100644
--- a/package.json
+++ b/package.json
@@ -111,6 +111,7 @@
     "semver": "5.5.1",
     "semver-stable": "2.0.4",
     "semver-utils": "1.1.2",
+    "showdown": "1.8.6",
     "simple-git": "1.102.0",
     "slugify": "1.3.1",
     "traverse": "0.6.6",
diff --git a/test/platform/github/__snapshots__/index.spec.js.snap b/test/platform/github/__snapshots__/index.spec.js.snap
index 11b8bb8a9d70a6d9c6326ce5779de5362b6c7381..7920ea6181fa073c8315fba384c479fc24908779 100644
--- a/test/platform/github/__snapshots__/index.spec.js.snap
+++ b/test/platform/github/__snapshots__/index.spec.js.snap
@@ -444,7 +444,7 @@ Object {
 }
 `;
 
-exports[`platform/github getPrBody(input) returns updated pr body 1`] = `"https://github.com/foo/bar/issues/5 plus also [a link](https://renovatebot.com/gh/foo/bar/issues/5)"`;
+exports[`platform/github getPrBody(input) returns updated pr body 1`] = `"<p><a href=\\"https://renovatebot.com/gh/foo/bar/issues/5\\">https://github.com/foo/bar/issues/5</a> plus also <a href=\\"https://renovatebot.com/gh/foo/bar/issues/5\\">a link</a></p>"`;
 
 exports[`platform/github getPrFiles() returns files 1`] = `
 Array [
diff --git a/test/platform/gitlab/__snapshots__/index.spec.js.snap b/test/platform/gitlab/__snapshots__/index.spec.js.snap
index 9b4783ef58705f17edbc315c7aaaa4f0e7dd0387..da1e9ba0e964547692a566b66ae5df25701b5487 100644
--- a/test/platform/gitlab/__snapshots__/index.spec.js.snap
+++ b/test/platform/gitlab/__snapshots__/index.spec.js.snap
@@ -243,7 +243,7 @@ Object {
 }
 `;
 
-exports[`platform/gitlab getPrBody(input) returns updated pr body 1`] = `"https://github.com/foo/bar/issues/5 plus also [a link](https://github.com/foo/bar/issues/5)"`;
+exports[`platform/gitlab getPrBody(input) returns updated pr body 1`] = `"<p><a href=\\"https://github.com/foo/bar/issues/5\\">https://github.com/foo/bar/issues/5</a> plus also <a href=\\"https://github.com/foo/bar/issues/5\\">a link</a></p>"`;
 
 exports[`platform/gitlab getPrFiles() returns files 1`] = `
 Array [
diff --git a/yarn.lock b/yarn.lock
index 645876d620a97f72b63ecbabd1342cd844ab32f8..6b13415a49b0dbd5c5b1bf0ff1225cde8399a688 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5144,6 +5144,7 @@ npm@6.4.1:
     cmd-shim "~2.0.2"
     columnify "~1.5.4"
     config-chain "~1.1.11"
+    debuglog "*"
     detect-indent "~5.0.0"
     detect-newline "^2.1.0"
     dezalgo "~1.0.3"
@@ -5158,6 +5159,7 @@ npm@6.4.1:
     has-unicode "~2.0.1"
     hosted-git-info "^2.7.1"
     iferr "^1.0.2"
+    imurmurhash "*"
     inflight "~1.0.6"
     inherits "~2.0.3"
     ini "^1.3.5"
@@ -5170,8 +5172,14 @@ npm@6.4.1:
     libnpx "^10.2.0"
     lock-verify "^2.0.2"
     lockfile "^1.0.4"
+    lodash._baseindexof "*"
     lodash._baseuniq "~4.6.0"
+    lodash._bindcallback "*"
+    lodash._cacheindexof "*"
+    lodash._createcache "*"
+    lodash._getnative "*"
     lodash.clonedeep "~4.5.0"
+    lodash.restparam "*"
     lodash.union "~4.6.0"
     lodash.uniq "~4.5.0"
     lodash.without "~4.4.0"
@@ -5210,6 +5218,7 @@ npm@6.4.1:
     read-package-json "^2.0.13"
     read-package-tree "^5.2.1"
     readable-stream "^2.3.6"
+    readdir-scoped-modules "*"
     request "^2.88.0"
     retry "^0.12.0"
     rimraf "~2.6.2"
@@ -6691,6 +6700,12 @@ shellwords@^0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
 
+showdown@1.8.6:
+  version "1.8.6"
+  resolved "https://registry.yarnpkg.com/showdown/-/showdown-1.8.6.tgz#91ea4ee3b7a5448aaca6820a4e27e690c6ad771c"
+  dependencies:
+    yargs "^10.0.3"
+
 signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@@ -7826,12 +7841,35 @@ yargs-parser@^10.1.0:
   dependencies:
     camelcase "^4.1.0"
 
+yargs-parser@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950"
+  dependencies:
+    camelcase "^4.1.0"
+
 yargs-parser@^9.0.2:
   version "9.0.2"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077"
   dependencies:
     camelcase "^4.1.0"
 
+yargs@^10.0.3:
+  version "10.1.2"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5"
+  dependencies:
+    cliui "^4.0.0"
+    decamelize "^1.1.1"
+    find-up "^2.1.0"
+    get-caller-file "^1.0.1"
+    os-locale "^2.0.0"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^2.0.0"
+    which-module "^2.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^8.1.0"
+
 yargs@^11.0.0:
   version "11.0.0"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b"