WP Manifestindependent plugin directory
manifest / content / byline-manager

Byline Manager WP Registry grade D+. High-severity findings · 3 findingsWP RegistryHigh-severity findings · 3 findingsOpen the reportD+

Manage an article's byline and author profiles in WordPress.

★ 6stars
34kcomposer installs
v0.7.0latest · 2mo 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/alleyinteractive/byline-manager/archive/refs/heads/production.zip

On Packagist as alleyinteractive/byline-manager:

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

Manage an article's byline and author profiles.

Requirements

Byline Manager requires PHP 8.1+. It is developed for use on WordPress 6.3+, though it may also work on earlier versions.

License

Byline Manager is released under the GNU General Public License, Version 3.

Byline Manager is a derivative work of Daniel Bachhuber's WordPress plugin Bylines (licensed GPL-3.0) and Automattic's Co-Authors Plus (licensed GPL-2.0).

Credits

Byline Manager is maintained by Alley Interactive.

Releases

18 releases.

Tag
Published
v0.7.0 latest
Aug 10, 2026 2mo ago
Sep 4, 2025 1 year ago
Jul 30, 2025 1 year ago
Jul 28, 2025 1 year ago
Mar 7, 2025 1 year ago
Oct 3, 2024 2 years ago
Jul 10, 2024 2 years ago
May 29, 2024 2 years ago
Apr 22, 2024 2 years ago
Feb 28, 2024 2 years ago
Feb 14, 2024 2 years ago
Feb 14, 2024 2 years ago
Feb 7, 2024 2 years ago
Dec 18, 2023 2 years ago
Sep 19, 2023 3 years ago
Sep 19, 2023 3 years ago
Aug 17, 2023 3 years ago
Nov 20, 2018 7 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

Byline Manager 0.7.0 · audited by WP Registry

High-severity findings.

1 high 1 medium 1 low
Audited release
0.7.0
Findings
3
Worst severity
high
Content hash
c457edb0f7614150e828000d…

Findings

  • high Authenticated (Author+) stored XSS via unsanitized REST byline text echoed on the_author_posts_link

    xss_stored

    register_post_meta() exposes the object meta key 'byline' on all post types in the REST API with a schema but no sanitize_callback. Gutenberg saves bylines through core/editor editPost({ meta: { byline: { profiles } } }), so an Author (no unfiltered_html) can store arbitrary HTML/JavaScript in profiles[].atts.text. The classic save_post path in set_byline() does apply wp_kses_post(); the REST path does not. Utils::get_byline_entries_for_post() turns those entries into TextProfile objects whose $link is ''. get_the_byline_posts_links() therefore takes the empty-href branch and returns $args['text'] (the display_name) with no esc_html. That helper is the return value of auto_integrate_byline_posts_links(), which is hooked to the_author_posts_link, so any theme calling the_author_posts_link() or get_the_author_posts_link() prints the payload to visitors. get_the_byline_links() likewise concatenates unescaped display_name (and GraphQL Byline.bylineText format LINKS uses it). get_the_byline() strips tags and the core/post-author block uses DOM nodeValue, so those consumers are safe. Subscriber cannot write the meta.

    inc/template-tags.php:82-94

    Recommendation

    Add a sanitize_callback (e.g. recursively wp_kses_post / sanitize_text_field on atts.text) and an auth_callback on register_post_meta('byline'). In get_the_byline_posts_links and get_the_byline_links always esc_html the display_name, including the empty-href and no-user_url branches. Keep the classic set_byline() kses path as defense in depth.

  • medium Authenticated (Contributor+) missing authorization to bind any WordPress user to a profile

    missing_capability

    The profile CPT uses capability_type 'post', so Contributor+ can create profile posts. set_profile_user_link() on save_post only verifies the set_user_link nonce; it never checks edit_users, list_users, or that the current user may modify the target account. It then calls Profile::update_user_link(), which writes post meta user_id and overwrites the victim's user meta byline_manager_{blog_prefix}profile_id with this profile's post ID (no check that the user is already linked). Observable: author_link for that user ID (override_author_link) now returns the attacker's profile permalink; Profile::get_by_user_id() returns the attacker's profile; rest_hydrate_profiles auto-fills that profile when the victim opens the editor. Author can publish the profile so the hijacked URL is publicly viewable; Contributor can still overwrite the usermeta from a draft. The Users metabox REST search (permission_callback is_user_logged_in) lets the attacker resolve any user's ID. Subscriber cannot save profiles.

    inc/admin-ui.php:213-241

    Recommendation

    Require current_user_can('edit_users') (or a dedicated cap) before update_user_link(), refuse to overwrite an existing link unless the operator can edit that user, and restrict the profile CPT capabilities so only editors/admins manage user bindings. Tighten GET /byline-manager/v1/users to list_users or edit_users.

  • low Authenticated (Subscriber+) unrestricted user enumeration via REST /byline-manager/v1/users

    information_disclosure

    register_rest_route() for GET /byline-manager/v1/users uses permission_callback is_user_logged_in only. rest_user_search() calls get_users() with search => $s . '*' and no number/role/capability cap, so a Subscriber or WooCommerce customer can list every account (including users who have never published, which core /wp/v2/users withholds without list_users). The JSON includes id, display_name, and whether the account is already linked to a profile. Empty s becomes search '*' and returns the full user table with no pagination. Emails and logins are not returned. Unauthenticated requests are rejected.

    inc/rest-api.php:38-46

    Recommendation

    Gate the endpoint on list_users or edit_posts plus list_users, require a minimum search fragment, and set a number limit. Do not return users the requester is not allowed to assign.

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.