Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
WordPressJune 23, 20264 min read

WordPress GraphQL Persisted Queries: Securing Your API

WordPress GraphQL performance and security depend on query control. Learn how to implement SHA-256 persisted queries to block malicious complexity-based DoS.

WordPressGraphQLWPGraphQLPerformanceSecurityAPIPHPCMS

Last month, our monitoring dashboard spiked during a routine deployment, showing that a single malicious actor was hammering our API with deeply nested, recursive GraphQL queries. By moving to persisted queries, we effectively neutralized these complexity-based Denial-of-Service attacks while simultaneously trimming our payload sizes by about 40%.

If you’re running a headless stack, you know the flexibility of WPGraphQL is a double-edged sword. While it’s powerful, it’s also a vector for resource exhaustion.

Why Persisted Queries are Non-Negotiable

When you expose a standard GraphQL endpoint, you’re allowing arbitrary query execution. A user can send a massive, recursive query that forces your server to perform expensive database joins or complex object resolution. This is exactly how complexity-based DoS attacks happen.

We first tried implementing a simple depth-limit filter, but it was brittle. Whenever we updated our front-end schema, the filter would break legitimate requests. We needed a strategy that allowed us to whitelist only known, tested queries. That’s where WordPress persisted queries come into play.

By requiring a SHA-256 hash instead of the full query string, the server only executes code that we’ve pre-approved. If a hash doesn't exist in our whitelist, the server returns an error. It’s a closed-loop system for your API.

Implementing the Whitelist Architecture

To implement this, we hook into the graphql_pre_execute filter. You’ll need a mapping of hashes to their corresponding query strings. I prefer storing these in a simple JSON file or a custom database table for faster lookups.

Here is the core logic for the implementation:

PHP
add_filter('graphql_pre_execute', function ($result, $query, $variables, $operation_name, $context) {
    #6A9955">// 1. Extract the hash from the request(usually in the 'extensions' field)
    $query_hash = $context->request->get_param('extensions')['persistedQuery']['sha256Hash'] ?? null;

    if (!$query_hash) {
        return new WP_Error('graphql_persisted_query_required', 'Only persisted queries are allowed.');
    }

    #6A9955">// 2. Lookup the hash in our whitelist(cached for performance)
    $allowed_query = wp_cache_get($query_hash, 'graphql_whitelist');
    
    if (false === $allowed_query) {
        $allowed_query = my_plugin_get_query_from_db($query_hash);
        wp_cache_set($query_hash, $allowed_query, 'graphql_whitelist', HOUR_IN_SECONDS);
    }

    if (!$allowed_query) {
        return new WP_Error('graphql_invalid_hash', 'The provided query hash is not whitelisted.');
    }

    return $result;
}, 10, 5);

This approach forces your client to "register" its queries during the build process. If you’re interested in broader API hardening, I’ve previously discussed WordPress Plugin Architecture for Fault Tolerance and API Resiliency, which complements this security layer by ensuring your site handles failures gracefully.

Managing Performance and Trade-offs

One catch: you need a build step in your CI/CD pipeline to generate these hashes. We use a simple Node.js script to hash our .graphql files and push them to a graphql_queries table in the WordPress database during deployment.

This adds roughly 200ms to our deployment time, but the performance gains in production are worth it. Because the server no longer has to parse and validate large, incoming strings, the overhead per request drops significantly.

However, be careful with how you handle cache invalidation. If you push a new version of the front-end that uses a new query hash before the WordPress database is updated, your users will see errors. Always deploy the database updates before the front-end assets.

If you’re working with complex data requirements, you might also look at WordPress REST API Performance: Brotli Compression for Headless SaaS to further optimize your transport layer.

Frequently Asked Questions

Can I still use GraphiQL for development? Yes, but you should wrap the whitelist logic in a conditional that checks current_user_can('manage_options') or environment constants. Never allow un-persisted queries in production.

What happens if a user guesses a hash? The probability of a SHA-256 collision is astronomically low. Even if they guess a valid hash, they are only executing a query you have already vetted for performance and security.

Does this break standard GraphQL introspection? Introspection is a separate query. You should whitelist the introspection query hash if you need it, or disable it entirely in production to prevent information leakage.

Final Thoughts

Implementing persisted queries is a significant move toward a production-grade API. It shifts the burden of query validation from runtime to build-time, which is exactly where it belongs. I’m still experimenting with how to handle dynamic arguments more effectively without bloating the whitelist, but for now, this pattern has saved us from several potential outages.

Don't treat your API as an open door. By locking down your GraphQL implementation, you ensure that your server only spends its cycles on work you've explicitly authorized. It’s one of the few places in WordPress engineering where the security overhead actually leads to a cleaner, faster architecture.

Back to Blog

Similar Posts

WordPressJune 23, 20264 min read

WordPress Plugin Architecture for Fault Tolerance and API Resiliency

Master WordPress plugin architecture and API resiliency by implementing graceful degradation. Prevent site-wide crashes when third-party services fail.

Read more
WordPressJune 23, 20264 min read

WordPress Multi-Tenancy: Implementing Row-Level Security with SQL Proxy

WordPress multi-tenancy requires robust data isolation. Learn how to implement Row-Level Security via SQL proxy middleware to secure your headless SaaS.

Read more
WordPressJune 23, 20264 min read

WordPress Performance: Implementing Read-Repair for Distributed Systems

WordPress performance and eventual consistency are hard to balance. Learn how to implement read-repair patterns to keep your headless architecture in sync.

Read more