HIGH data exposurehapijwt tokens

Data Exposure in Hapi with Jwt Tokens

Data Exposure in Hapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability

Hapi is a rich framework for building HTTP services in Node.js, and it commonly uses JWT tokens for authentication and authorization. When JWT tokens are handled incorrectly within Hapi, sensitive data can be exposed through multiple vectors. A misconfigured validation strategy, insecure transmission, or improper storage can lead to token leakage or token misuse, resulting in account takeover or privacy violations.

One common pattern in Hapi is to authenticate requests using a JWT payload attached to the request state or using the auth scope provided by the hapi-auth-jwt2 plugin. If the server does not validate the token signature strictly, an attacker could supply a tampered token and gain unauthorized access to protected resources. For example, missing or weak audience (aud) and issuer (iss) checks may allow an attacker to present a token issued for a different service to this API.

Data exposure can also occur when tokens are transmitted over non-HTTPS channels or when debugging endpoints inadvertently log token contents. Hapi servers that log request state or include raw token data in error responses may unintentionally expose tokens in logs or browser consoles. Additionally, storing sensitive claims (such as roles or permissions) in the JWT payload without encryption can lead to information disclosure if the token is intercepted, because JWTs are typically base64-encoded but not encrypted by default.

Another exposure risk arises from improper token scope handling. If a Hapi route that requires limited-scope access receives a token with broader privileges and the server does not enforce scope checks, attackers can perform privilege escalation. The hapi-auth-jwt2 plugin supports scope validation, but developers must explicitly configure it. Failure to validate token expiration (exp) or not refreshing tokens securely can result in the use of stale tokens, increasing the window for data exposure.

Middleware configuration mistakes can compound these issues. For instance, applying authentication strategies globally when only certain routes need protection increases the attack surface. Similarly, failing to set the isSecure flag for cookies when using cookie-based token storage can expose tokens to cross-site scripting (XSS) attacks. These misconfigurations make it easier for an attacker to steal or manipulate JWT tokens and access sensitive data served by the Hapi endpoints.

Jwt Tokens-Specific Remediation in Hapi — concrete code fixes

To mitigate data exposure risks with JWT tokens in Hapi, apply strict validation and secure handling practices. Use the hapi-auth-jwt2 plugin with strong options, validate all standard claims, and avoid logging or exposing token data. The following examples illustrate secure configurations and route handling.

Secure JWT Strategy Configuration

Define a strategy that enforces signature verification, audience, issuer, and scope checks. This prevents acceptance of tampered or misissued tokens.

const Hapi = require('@hapi/hapi');
const Jwt = require('@hapi/jwt');

const validateToken = (decoded, request, h) => {
  // Perform additional application-level checks if needed
  return { isValid: true, credentials: decoded };
};

const init = async () => {
  const server = Hapi.server({
    port: 3000,
    host: 'localhost'
  });

  await server.register(Jwt);

  server.auth.strategy('jwt', 'jwt', {
    keys: process.env.JWT_PUBLIC_KEY || 'your-256-bit-secret',
    verify: {
      aud: 'my-api.example.com',
      iss: 'https://auth.example.com',
      scope: 'read write'
    },
    validate: validateToken
  });

  server.auth.default('jwt');

  server.route({
    method: 'GET',
    path: '/profile',
    options: {
      auth: 'jwt',
      handler: (request, h) => {
        // request.auth.credentials contains the validated decoded payload
        return { user: request.auth.credentials.name, scope: request.auth.credentials.scope };
      }
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

init().catch((err) => {
  console.error('Server failed to start:', err);
});

Mitigate Logging and Transmission Risks

Ensure tokens are transmitted only over HTTPS and avoid logging raw tokens. Configure Hapi to use secure cookies when storing tokens on the client side, and sanitize error responses.

const Hapi = require('@hapi/hapi');
const Cookie = require('@hapi/cookie');
const Jwt = require('@hapi/jwt');

const init = async () => {
  const server = Hapi.server({
    port: 3000,
    host: 'localhost',
    routes: {
      security: {
        hsts: {
          maxAge: 3600,
          includeSubdomains: true
        }
      }
    }
  });

  await server.register([Jwt, Cookie]);

  server.auth.strategy('jwt', 'jwt', {
    keys: process.env.JWT_PUBLIC_KEY,
    verify: {
      aud: 'my-api.example.com',
      iss: 'https://auth.example.com',
      scope: 'read write'
    }
  });

  server.auth.strategy('cookie', 'cookie', {
    cookie: {
      name: 'token',
      password: process.env.COOKIE_PASSWORD,
      isSecure: true,
      isHttpOnly: true,
      path: '/'
    }
  });

  server.auth.default({
    strategy: 'jwt',
    mode: 'try'
  });

  server.route({
    method: 'GET',
    path: '/secure-data',
    options: {
      auth: {
        strategies: ['jwt'],
        scope: ['read']
      },
      handler: (request, h) => {
        if (!request.auth.isAuthenticated) {
          return { error: 'Unauthorized' };
        }
        return { data: 'Sensitive data safely delivered' };
      }
    }
  });

  await server.start();
  console.log('Secure server running on %s', server.info.uri);
};

init().catch((err) => {
  console.error('Server failed to start:', err);
});

Scope and Claim Validation

Always validate scopes and claims on the server side and avoid trusting the client. Enforce scope checks for each route and reject tokens with missing or insufficient scope.

const Hapi = require('@hapi/hapi');
const Jwt = require('@hapi/jwt');

const validateScopes = (decoded, request, h) => {
  const requiredScopes = request.route.settings.auth.payload.scope || [];
  const tokenScopes = decoded.scope || [];
  const hasScope = requiredScopes.every((scope) => tokenScopes.includes(scope));
  return { isValid: hasScope, credentials: decoded };
};

const init = async () => {
  const server = Hapi.server({
    port: 3000,
    host: 'localhost'
  });

  await server.register(Jwt);

  server.auth.strategy('jwt', 'jwt', {
    keys: process.env.JWT_PUBLIC_KEY,
    verify: {
      aud: 'my-api.example.com',
      iss: 'https://auth.example.com',
      scope: ['read', 'write']
    },
    validate: validateScopes
  });

  server.route({
    method: 'POST',
    path: '/admin',
    options: {
      auth: {
        strategies: ['jwt'],
        scope: ['write']
      },
      handler: (request, h) => {
        return { message: 'Admin action authorized' };
      }
    }
  });

  await server.start();
  console.log('Server running with scope validation');
};

init().catch((err) => {
  console.error('Server failed to start:', err);
});

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

How does middleBrick detect JWT-related data exposure in Hapi APIs?
middleBrick runs black-box scans against the unauthenticated attack surface of your Hapi API, including endpoints that accept or return JWT tokens. It checks for missing validation of audience, issuer, and scope claims, as well as insecure transmission indicators and logging risks, and reports findings with remediation guidance.
Can I integrate middleBrick into my CI/CD pipeline to prevent JWT configuration regressions?
Yes. With the Pro plan, you can add the GitHub Action to your CI/CD pipeline to fail builds if the security score drops below your chosen threshold. The Action scans staging APIs before deploy and provides JSON output you can consume in your pipeline scripts.