Security · Security Hardening

A production hardening checklist for your GraphQL router

Disable introspection. Turn off dev mode. Configure CORS allowlists. Enable Redis-backed rate limiting. Restrict operations to pre-approved queries. All in YAML.

Rate limiting requires a Redis instance. TLS requires certificates.

Available onFreeProEnterprise

The problem

Default configurations are built for development, not production

Every convenience feature enabled during development becomes an attack surface in production. Most teams do not know which defaults to change before they ship.

Default configurations expose more than production needs

Introspection, file uploads, and open CORS are enabled by default. Development mode is off by default, but worth confirming before you ship. Each is a feature useful during development and an attack surface in production.

No rate limiting means subgraphs absorb any load

Without rate limiting, a burst of requests — automated or not — passes directly to subgraphs. At scale, this causes service degradation or outages for all users.

Open CORS lets any origin trigger cross-site requests

The default CORS configuration allows all origins. In a production deployment that accepts credentials, this enables cross-site request forgery from any page a user visits.

Our solution

Systematic attack surface reduction

The Cosmo Security Hardening Guide provides a configuration checklist for production deployments. Each setting addresses a specific attack vector with a concrete YAML change.

Production hardening checklist

  1. Disable introspection with introspection.enabled: false to hide the API schema from clients.

  2. Set dev_mode: false. Development mode enables Advanced Request Tracing (ART), which can expose sensitive information, along with pretty log output.

  3. Set file_upload.enabled: false if your API does not need multipart file upload support.

  4. Configure CORS with an explicit allow_origins list, specific allow_methods, and trusted allow_headers.

  5. Enable Redis-backed rate limiting with GCRA algorithm. Configure rate, burst, and period for your traffic profile.

  6. Consider enabling block_non_persisted_operations to limit execution to pre-approved operations only.

  7. Enable TLS and consider Config Signing for a fully hardened production deployment.

Rate limiting requires Redis. TLS requires certificates. All other settings need only YAML.

Security Hardening

Before & After

DefaultHardened
Introspection enabled by default in productionintrospection.enabled: false
All origins allowed by CORSExplicit allow_origins and allow_headers list
No rate limiting on subgraph trafficGCRA rate limiting via Redis with configurable rate and burst
Any GraphQL operation acceptedblock_non_persisted_operations restricts to approved queries

Rate limiting

Per-key overrides for different consumers

Set a global rate, burst, and period. Use key_suffix_expression to derive a key from JWT claims. Define overrides with matching regex patterns to give specific consumer types different limits. The first matching override wins.

Four steps to a hardened router

01
Three lines, less attack surface.

Disable exposure

Set introspection.enabled: false, dev_mode: false, and file_upload.enabled: false. These three settings remove attack surface that production APIs do not need: schema discovery, ART exposure, and multipart upload pressure.

02
Explicit allowlists, not wildcards.

Lock down origins

Configure cors.allow_origins with your specific domains, cors.allow_methods to POST and GET only, and cors.allow_headers to the headers your clients use. The default allows all origins. Use explicit allowlists in production.

03
GCRA via Redis. Test first.

Enable rate limiting

Set rate_limit.enabled: true with a Redis URL. The GCRA (leaky bucket) algorithm uses three parameters: rate (requests per period), burst (allowed burst above rate), and period (time window, e.g. 1s). Test limits before applying to production.

04
Allowlist operations. Block the rest.

Restrict operations

Upload persisted operations via the wgc CLI and set security.block_non_persisted_operations.enabled: true. Only pre-approved operations execute. Also consider block_mutations and block_subscriptions if your API does not use them.

Hardening controls

Every attack vector addressed

Configuration-driven controls with no code changes in subgraphs.

Schema and mode controls

introspection.enabled: false hides the schema. dev_mode: false disables ART and pretty log output. file_upload.enabled: false removes multipart pressure from the router.

CORS allowlists

Specify allow_origins with your trusted domains, allow_methods with POST and GET, and allow_headers with the specific headers your clients send. Open CORS is the default. Use explicit allowlists in production.

GCRA rate limiting

Redis-backed GCRA (leaky bucket) rate limiting. Set rate, burst, and period globally. Use key_suffix_expression to derive per-consumer keys from JWT claims and define per-key overrides for different traffic tiers.

Operation restrictions

Upload pre-approved operations via wgc CLI and enable block_non_persisted_operations. Add block_mutations or block_subscriptions if those operation types are not used by your API.

Harden your router before you ship

Follow the checklist in the hardening guide. Every setting is a YAML change.

FAQ

Security Hardening on Cosmo Router

Full checklist in the Security Hardening Guide.