WP Manifestindependent plugin directory
manifest / integrations / wp-graphql-cors

WPGraphQL CORS WP Registry grade B-. Medium-severity findings · 3 findingsWP RegistryMedium-severity findings · 3 findingsOpen the reportB-

Makes WP GraphQL's authetication "just work". It does this by customizing the CORS headers.

★ 125stars
2.1.1latest · 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/funkhaus/wp-graphql-cors/archive/refs/heads/master.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

The primary purpose of this plugin is to make the WP GraphQL plugin authentication "just work". It does this by allowing you set the CORS headers that GraphQL will accept, which means that WordPress's default authentication cookies will be accepted.

This means that if a user is logged into WordPress, they will be able to see things like draft and private pages/posts via GraphQL.

Features

  • Allows WP-GraphQL to accept default WordPress cookies
  • Works across multiple domains (so you can have multiple frontends connected to one backend)
  • Allows you to filter out specific cookies for added security (perhaps you don't want to use this for WordPress authentication but do want to access other cookies)
  • Allows you to customize the GraphQL endpoint
  • Extends WP GraphQL to have a logout and login mutation
  • Allows you to filter out which cookies are allowed

Installation

  1. Requires WP GraphQL.
  2. Upload this plugin to WordPress.
  3. Config your GraphQL client (probably Apollo) to include credentials in requests. Generally this is a setting under httpLinkOptions and look to set credentials = "include".

Now if the browser is currently logged into WordPress, WP GraphQL will allow access to authenticated data.

Documentation

If all you want to do is allow draft, private and page previews to be viewed from the frontend, setting Send site credentials. and Add Site Address to "Access-Control-Allow-Origin" header to true will do this.

You'll also need to config your GraphQL client (probably Apollo) to include credentials in requests. Generally this is a setting under httpLinkOptions and look to set credentials = "include".

Logout Mutation

If enabled in the settings, WP GraphQL will have a new mutation available to allow a user to logout. This is useful if you want to build a "logout" button on a sites frontend.

mutation {
    logout(input: {clientMutationId = "anything unique"}){
        clientMutationId
        status
    }
}

Login Mutation

If enabled in the settings, WP GraphQL will have a new mutation available to allow a user to login.

mutation {
    loginWithCookies(input: {clientMutationId: "", login: "", password: ""}) {
        clientMutationId
        status
    }
}

Releases

6 releases.

Tag
Published
2.1.1 latest
Oct 3, 2023 3 years ago
2.1
Aug 19, 2022 4 years ago
2.0
Apr 30, 2021 5 years ago
Sep 8, 2020 6 years ago
Aug 7, 2020 6 years ago
Feb 23, 2020 6 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

WPGraphQL CORS 2.1 · audited by WP Registry

Medium-severity findings.

2 medium 1 low
Audited release
2.1
Findings
3
Worst severity
medium
Content hash
921341ec9cb6dc96e5fb0b50…

Findings

  • medium Block-unauthorized-domains origin gate is dead because of PHP operator precedence

    auth_bypass

    The plugin documents a "Block unauthorized domains" checkbox (acao_block_unauthorized) that is supposed to refuse GraphQL operations whose Referer/Origin is not on the allowlist. wpgraphql_cors_api_authentication implements that by throwing a GraphQL UserError, but the condition is `$allowed_origin == null && ! 'on' === get_graphql_setting(...)`. Unary `!` has higher precedence than `===`, so this evaluates as `($allowed_origin == null) && (false === 'on'|'off')` and is never true. PHP confirms the throw is unreachable for both 'on' and 'off'. The sibling header filter still changes Access-Control-Allow-Origin (wildcard vs siteurl), which only affects whether foreign JavaScript can read the body. The GraphQL operation itself still runs for any Origin, including omitted Origin (curl/Postman). That is the only server-side origin firewall; prefix matching in wpgraphql_cors_get_allowed_origin (HTTP_REFERER preferred over HTTP_ORIGIN, substr prefix after stripping the scheme) is therefore never backed by a reject. Downstream: with Send-site-credentials / loginWithCookies enabled, unauthorized-origin POSTs still execute cookie-authenticated work; even without cookies, the advertised API lock does not apply.

    includes/process-request.php:155-163

    Recommendation

    Compare with explicit parentheses and the same sense as the header helper: `if ( null === $allowed_origin && 'on' === get_graphql_setting( 'acao_block_unauthorized', 'off', 'graphql_cors_settings' ) ) { throw ... }`. Prefer the Origin header (not Referer) and parse_url host+scheme+port equality instead of scheme-stripped prefix matching. Do not treat CORS headers as a substitute for refusing the operation.

  • medium Public logout mutation calls wp_logout() with no nonce or origin check

    csrf

    When graphql_cors_settings.logout_mutation is enabled (README presents this as the way to build a frontend logout button), register_graphql_mutation('logout') exposes a RootMutation with empty inputFields. mutateAndGetPayload ignores the GraphQL viewer and always calls wp_logout(), which destroys the current session and emits expired AUTH / logged_in Set-Cookie headers. There is no wp_verify_nonce, no capability check, and no Origin allowlist check inside the resolver. The plugin’s only origin reject (wpgraphql_cors_api_authentication) never fires, so a third-party site can POST mutation { logout(input:{}) { status } } to /graphql. wp_clear_auth_cookie does not require the request to have been authenticated: it blindly expires the WordPress cookie names. With loginWithCookies (default samesite_mode None) the browser also sends the session on cross-site fetch; even with Lax cookies, a top-level form POST is a first-party navigation whose Set-Cookie response can still clear the session. Core wp-login.php?action=logout requires a nonce; this mutation does not.

    includes/logout-mutation.php:16-41

    Recommendation

    Before wp_logout(), require a logged-in user and a CSRF token (WP nonce in a custom header, or a same-site cookie double-submit) and refuse the mutation when wpgraphql_cors_get_allowed_origin() is null. Do not clear auth cookies for unauthenticated or unauthorized-origin requests. Keep logout_mutation off unless those checks exist.

  • low Plugin header, constant, and readme versions disagree

    version_mismatch

    The Plugin Name header Version is 2.1, WPGRAPHQL_CORS_VERSION is hardcoded to 1.1.1, readme.txt Stable tag is 1.1.0, and the GitHub tag/distribution is 2.1.1. WP admin, inventory, and any update check that reads the header will misidentify the installed code. The mismatch is unchanged on upstream master.

    wp-graphql-cors.php:8-26

    Recommendation

    Set the plugin header Version, WPGRAPHQL_CORS_VERSION, and readme.txt Stable tag to the same value as the git tag (2.1.1) and keep them in lockstep on future releases.

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.