How to Configure Rate Limiting Protection in OpenCTI: A Complete Guide

OpenCTI applies Express rate-limit middleware to protect its GraphQL API, configurable via JSON files or environment variables using app:rate_protection settings.

To configure rate limiting protection in OpenCTI, you modify the rate_protection object within the platform's hierarchical configuration system. The OpenCTI-Platform/opencti repository implements this protection using the express-rate-limit package, reading window duration and request thresholds from the nconf configuration layer.

Understanding OpenCTI's Rate Limiting Implementation

OpenCTI embeds rate limiting directly into its HTTP platform initialization. The protection activates automatically when the server starts, applying a global limit to all incoming API requests.

Core Middleware Configuration

In src/http/httpPlatform.js (lines 102-107), OpenCTI instantiates the rate limiter using values from the configuration store:

const limiter = rateLimit({
  windowMs: nconf.get('app:rate_protection:time_window') * 1000, // seconds
  limit: nconf.get('app:rate_protection:max_requests'),
  handler: (req, res) => {
    res.status(429).send({ message: 'Too many requests, please try again later.' });
  },
});
app.use(limiter);

The middleware intercepts every request and tracks client IPs. When requests exceed the configured threshold within the time window, the server responds with HTTP 429 and a JSON error message.

Default Configuration Values

The baseline settings reside in config/default.json (lines 101-104):

"rate_protection": {
  "time_window": 1,
  "max_requests": 10000
}

By default, OpenCTI permits 10,000 requests per second. This high threshold accommodates bulk ingestion operations but should be reduced for production deployments exposed to untrusted networks.

Configuration Methods for Rate Limiting Protection

OpenCTI uses nconf to merge configuration sources hierarchically: command-line arguments override environment variables, which override JSON files. You can configure rate limiting through three primary methods.

JSON Configuration Files

Create or modify environment-specific JSON files (e.g., production.json) to set permanent limits:

{
  "app": {
    "rate_protection": {
      "time_window": 60,
      "max_requests": 500
    }
  }
}

Load the custom configuration using the -c flag:

node build/index.js -c config/production.json

Environment Variables

OpenCTI maps hierarchical configuration keys to environment variables using double underscores (__) as separators. The configuration loader in src/config/conf.js processes these with lowerCase: true.

Set rate limiting via environment variables:

export APP__RATE_PROTECTION__TIME_WINDOW=60
export APP__RATE_PROTECTION__MAX_REQUESTS=300

Environment variables take precedence over JSON file values, making them ideal for containerized deployments where configuration changes frequently.

Command Line Options

While the -c flag specifies which configuration file to load, individual configuration overrides can be passed via environment variables when starting the platform. For Docker deployments, pass variables directly to the container.

Practical Configuration Examples

Docker Deployment with Custom Limits

Mount a custom configuration file when running the OpenCTI platform container:

docker run --rm \
  -e NODE_ENV=production \
  -v $(pwd)/custom-rate-limit.json:/app/config/custom.json \
  opencti/platform:latest \
  -c config/custom.json

Contents of custom-rate-limit.json:

{
  "app": {
    "rate_protection": {
      "time_window": 30,
      "max_requests": 200
    }
  }
}

Docker Compose Configuration

Define rate limiting in your docker-compose.yml for persistent deployments:

services:
  opencti:
    image: opencti/platform:latest
    environment:
      - APP__RATE_PROTECTION__TIME_WINDOW=60
      - APP__RATE_PROTECTION__MAX_REQUESTS=500
      - NODE_ENV=production
    ports:
      - "8080:8080"

Programmatic Verification

Test your configuration by simulating high request volume:


# Send 150 requests in parallel (adjust based on your limit)

for i in {1..150}; do
  curl -s -o /dev/null -w "%{http_code}\n" \
    http://localhost:8080/graphql \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"query":"{ about { version } }"}' &
done
wait

If configured correctly, requests exceeding your max_requests threshold should return 429 status codes.

How the Rate Limiter Works

When a client connects to the OpenCTI API, the Express rate-limit middleware maintains an in-memory store tracking request counts per IP address. The middleware compares the current request count against the max_requests value within the rolling time_window (converted to milliseconds).

If the threshold is exceeded, the handler function executes immediately, sending HTTP 429 Too Many Requests with a JSON error body. Successful requests continue to the GraphQL resolver chain. The limiter applies globally to all routes in the default implementation, protecting both authentication endpoints and data ingestion APIs equally.

Summary

  • OpenCTI implements rate limiting via express-rate-limit middleware in src/http/httpPlatform.js, reading configuration from the nconf hierarchy.
  • Default settings allow 10,000 requests per second (time_window: 1, max_requests: 10000), defined in config/default.json.
  • Configure limits via JSON files (app.rate_protection object), environment variables (APP__RATE_PROTECTION__TIME_WINDOW and APP__RATE_PROTECTION__MAX_REQUESTS), or Docker environment settings.
  • Exceeding the configured threshold returns HTTP 429 with the message "Too many requests, please try again later."

Frequently Asked Questions

What are the default rate limiting values in OpenCTI?

By default, OpenCTI permits 10,000 requests per 1-second window. These values are hardcoded in config/default.json under the rate_protection key, with time_window set to 1 (second) and max_requests set to 10000. This generous default accommodates high-volume data ingestion but should be reduced for production environments facing the public internet.

How do I completely disable rate limiting in OpenCTI?

While OpenCTI does not provide an explicit "disable" flag, you can effectively disable rate limiting by setting the max_requests value to an extremely high number (e.g., 999999999) or by setting the time_window to a very large value. Alternatively, since the middleware is applied conditionally based on configuration, setting max_requests to 0 may disable the limiter depending on the express-rate-limit version, though this is not officially documented and should be tested in a non-production environment first.

Can I configure different rate limits for different API endpoints?

The default implementation in src/http/httpPlatform.js applies a global rate limiter to all routes via app.use(limiter). To implement endpoint-specific limits, you would need to modify the source code to create multiple rateLimit instances with different configurations and apply them to specific route patterns (e.g., app.use('/graphql', strictLimiter) vs app.use('/health', permissiveLimiter)). This requires maintaining a fork or custom build of the platform, as the standard distribution does not expose per-route rate limiting through configuration files.

Why is my OpenCTI instance returning HTTP 429 errors?

HTTP 429 errors indicate that the client has exceeded the configured rate limits defined by app:rate_protection:max_requests within the app:rate_protection:time_window period. This commonly occurs during bulk import operations, automated scanning, or when multiple users share the same egress IP address. To resolve this, either reduce the request frequency from the client side, or increase the max_requests value (or expand the time_window) in your OpenCTI configuration via environment variables or JSON config files. Check the server logs to confirm which specific limit is being triggered.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →