WP Manifestindependent plugin directory
manifest / content / hm-post-history

HM Post History WP Registry grade B. Medium-severity findings · 1 findingWP RegistryMedium-severity findings · 1 findingOpen the reportB

Adds a widget and REST endpoint for the purpose of displaying post revisions inline on the frontend.

★ 7stars
152composer installs
v1.4.3latest · 3 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/humanmade/hm-post-history/archive/refs/heads/main.zip

On Packagist as humanmade/hm-post-history:

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

Post History

This widget allows visitors to easily diff posts against their earlier revisions, displaying diffs of HTML inline.

It should be plug and play: Just add the widget to a sidebar that will appear on a page or post. It will detect everything it needs. If you have more complex needs, the code is heavily documented and includes many filters to modify behavior. If the widget's design doesn't suit your purposes, its class is easily extendable, with methods for generating all of the necessary HTML.

Release process

This plugin requires a small amount of JS and CSS in order to work properly, and these must be built on deployment. To ensure a tagged release includes these built assets, follow the process below for each release:

  1. Merge all PRs to be included in the release into main
  2. Open a PR to bump the version numbers in package.json and hm-post-history.php to the next appropriate version
  3. Once the PR is merged, create a tag on main with the version number, e.g. v1.4.0
  4. GitHub Actions should auto-build the frontend assets and reset that tag to push to the bundled code

Check the build output in the Actions tab to see whether it works or not.

Development Builds

To test the plugin on a deployed instance via composer, register the repository as a VCS source, and set your humanmade/hm-post-history dependency to track the dev-develop-built branch source.

Merge PRs which require development testing into the develop branch, and they will be automatically built and pushed to that develop-built branch using a GitHub Action.

If code which is not intended for release ends up on develop, force-reset both develop and develop-built to match the latest main.

Releases

5 releases.

Tag
Published
v1.4.3 latest
Dec 23, 2022 3 years ago
Sep 29, 2022 4 years ago
Sep 29, 2022 4 years ago
1.3
May 26, 2022 4 years ago
1.0
May 6, 2022 4 years ago

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

B grade

Security

HM Post History 1.4.2 · audited by WP Registry

Medium-severity findings.

1 medium
Audited release
1.4.2
Findings
1
Worst severity
medium
Content hash
ca2c0b2f22a8145ac060fec0…

Findings

  • medium Subscriber+ REST revisions endpoint discloses full HTML, autosaves, and password-protected content

    information_disclosure

    register_rest_route( 'post-history/v1', '/revisions/(?P<id>\d+)' ) is a public GET once the route exists. REST\bootstrap() is attached from conditional_bootstrap() on init whenever should_enable() passes — that helper is only is_user_logged_in() plus “some post type supports hm-post-history”, which setup_post_types() grants to every type that already supports revisions (post and page by default). The widget does not have to be placed. revisions_request_permissions_callback then short-circuits: if get_post_status( $id ) === 'publish' it returns true with no current_user_can('read_post'), no current_user_can('edit_post'), and no post_password / post_password_required() check. Password-protected posts remain status publish, so their revision bodies (typically including the current protected content) are returned to a Subscriber who cannot see the post on the front end and cannot read it from core /wp/v2/posts. Non-publish posts fall through to edit_post; missing parents return true. get_revisions_query() is WP_Query( post_parent, post_type=revision, post_status=inherit ) with attacker-controlled per_page (absint, no max) and does not exclude autosaves (post_name {id}-autosave-v1), so in-progress unpublished edits of a published post are included. build_revisions_list() puts apply_filters( 'the_content', $revision->post_content ) plus the reviser's display_name into JSON. Core WP_REST_Revisions_Controller::get_items_permissions_check requires edit_post for this data. insert_server_side_settings() localizes a wp_rest nonce on every frontend page for logged-in users, so the Subscriber does not need the widget UI. Unauthenticated callers do not register the route on a default install. Consequence is confidentiality of revision HTML / protected bodies / autosaves, not RCE — hence medium, matching Subscriber+ revision/protected-content disclosure CVEs.

    inc/rest.php:32-60,71-83,93-109,143-166

    Recommendation

    Align with core revisions REST: require current_user_can( 'edit_post', $parent_id ) unless you truly intend public history, in which case still (1) deny when post_password is set unless the requester may read the post (current_user_can('read_post') or a valid password), (2) exclude autosaves (wp_is_post_autosave / post_name NOT LIKE '%-autosave-%'), (3) do not treat a missing parent as allowed, (4) cap per_page. Register the route unconditionally and put the real gate in permission_callback so login-only route registration is not the only unauth control. Do not localize the REST nonce on every page if the widget is absent.

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.