HIGH api key exposurestrapitypescript

Api Key Exposure in Strapi (Typescript)

Api Key Exposure in Strapi with Typescript — how this specific combination creates or exposes the vulnerability

Strapi is a headless CMS that often stores sensitive credentials such as database passwords and third-party service tokens within its codebase or environment configuration. When developers write business logic in Typescript controllers or services, they may inadvertently expose API keys through insecure logging, client-side serialization, or overly permissive GraphQL/REST field resolvers.

One common pattern is fetching a third-party service key from environment variables and passing it directly to a frontend-serializable object or returning it in an API response. Because Strapi applications built with Typescript can include custom controllers and services, a developer might write code like the following, accidentally returning a key to an unauthenticated caller:

// src/api/integration/controllers/integration.controller.ts
import { createCoreController } from '@strapi/strapi';

export default createCoreController('api::integration.integration', ({ strapi }) => ({
  async findOne(ctx) {
    const entry = await strapi.entityService.findOne('api::integration.integration', ctx.params.id);
    // Vulnerable: exposing an API key to the client
    return { ...entry, apiKey: process.env.THIRD_PARTY_API_KEY };
  },
}));

Additionally, Strapi’s Typescript services may be used to call external APIs, and if error handling in Typescript does not sanitize key material from stack traces or logs, keys can be leaked through application logs or error responses. For example, a poorly handled request may log the full environment configuration including keys:

// src/api/webhook/controllers/webhook.controller.ts
export async function handleWebhook(ctx) {
  const payload = ctx.request.body;
  strapi.log.info(`Processing webhook with config: ${JSON.stringify(process.env)}`);
  // ... rest of logic
}

Another exposure vector is through OpenAPI spec generation when Strapi plugins introspect environment variables for runtime documentation, and the Typescript layer exposes these values through an introspection endpoint. Even when using Strapi’s built-in security controls, a developer using Typescript must ensure that any middleware or policy does not forward keys to the client or include them in serialized JSON that traverses the network.

Because middleBrick scans the unauthenticated attack surface and performs both OpenAPI/Swagger spec analysis and runtime checks, it can detect endpoints where an API key appears in responses or documentation. The scanner’s checks for Data Exposure and Unsafe Consumption are particularly effective at highlighting places where secrets leak through API surfaces built with Typescript in Strapi.

Typescript-Specific Remediation in Strapi

Remediation focuses on ensuring that API keys never leave the server environment and that Typescript code enforces strict data filtering. Instead of returning raw environment variables, use server-side-only methods to access secrets and transform responses before serialization.

First, use Strapi’s built-in configuration and runtime environment access without exposing keys. Create a service that handles external calls without leaking credentials:

// src/api/integration/services/integration.ts
export const callExternalService = async (recordId: number) => {
  const { apiKey } = strapi.config.get('plugin.thirdParty');
  const response = await fetch('https://api.example.com/data', {
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  if (!response.ok) {
    throw new Error('External service unavailable');
  }
  return response.json();
};

Then, in your controller, only return safe, filtered data to the client:

// src/api/integration/controllers/integration.controller.ts
import { createCoreController } from '@strapi/strapi';
import { callExternalService } from '../services/integration';

export default createCoreController('api::integration.integration', ({ strapi }) => ({
  async findOne(ctx) {
    const entry = await strapi.entityService.findOne('api::integration.integration', ctx.params.id);
    // Safe: only non-sensitive fields are returned
    const { apiKey, ...safeEntry } = entry;
    return safeEntry;
  },
}));

For logging, avoid serializing environment objects and scrub sensitive fields explicitly:

// src/api/webhook/controllers/webhook.controller.ts
export async function handleWebhook(ctx) {
  const payload = ctx.request.body;
  // Safe: log only necessary metadata
  strapi.log.info(`Processing webhook for entity ${payload.entityId}`);
  // ... rest of logic
}

When using middleBrick’s CLI or Web Dashboard, you can validate that these fixes work by rescanning the endpoint. The CLI allows you to automate checks within a TypeScript project:

npx middlebrick scan https://your-strapi-api.com/api/integration --output json

Pro plan users can enable continuous monitoring to ensure that any future changes to Typescript controllers do not reintroduce key exposure. The GitHub Action can be configured to fail builds if a scan detects exposed secrets, providing a CI/CD gate before deployment.

Frequently Asked Questions

Can middleBrick detect API keys exposed in Strapi Typescript controllers?
Yes, middleBrick scans unauthenticated endpoints and can identify API keys in responses, documentation, and logging patterns common in Strapi with Typescript.
Does middleBrick provide automatic fixes for exposed keys in Strapi?
No, middleBrick detects and reports findings with remediation guidance. It does not automatically modify Strapi Typescript code or environment configurations.