HIGH api key exposureadonisjssaml

Api Key Exposure in Adonisjs with Saml

Api Key Exposure in Adonisjs with Saml

When AdonisJS applications consume SAML-based identity providers, API keys can be inadvertently exposed through session management, route handling, or misconfigured service providers. AdonisJS does not inherently manage SAML flows; integrations typically rely on libraries that process SAML responses and establish local sessions. If developers store or log API keys—such as those used to call downstream services—within the SAML session or attach them to assertions, those keys may be serialized, persisted, or transmitted in ways that increase exposure risk.

For example, consider an AdonisJS route that uses a SAML-validated user identity to call a third-party API. If the route retrieves an API key from a configuration or environment variable and attaches it to the session object for later use, the key may be written to server-side session stores or exposed inadvertently through debug endpoints or logs. A misconfigured session serializer might also include the key in URLs or query parameters, which can be captured in browser histories, proxy logs, or referrer headers.

Another scenario involves SAML attribute statements that inadvertently carry sensitive metadata. If an identity provider includes non‑user attributes (such as service tokens or internal identifiers) in the SAML response, and the AdonisJS handler merges those attributes directly into application state or headers, any downstream API calls that rely on those headers may leak credentials. This becomes particularly risky when the application uses the same session for both UI rendering and background service calls, as the same authenticated context is reused across different trust boundaries.

Middleware that enforces authentication for certain routes but not for others can also create inadvertent exposure paths. An endpoint that expects a SAML-authenticated user might still allow unauthenticated access to a health or status route that returns system configuration, including API keys or connection strings. Because SAML responses are often treated as trusted once validated, developers may overlook the need to scope and isolate sensitive data within distinct request contexts.

To detect these patterns, middleBrick scans the unauthenticated attack surface of an AdonisJS endpoint that integrates SAML, looking for insecure session handling, verbose error messages, and overly permissive route definitions. The tool checks whether API keys are present in logs, whether they are transmitted in URLs, and whether they survive across redirects or SAML assertions. By correlating SAML flow behavior with runtime observations, middleBrick helps surface where credential leakage may occur without requiring access to source code or configuration files.

Saml-Specific Remediation in Adonisjs — concrete code fixes

Remediation focuses on ensuring SAML sessions carry only the minimum required user claims and never include service-level API keys. Store secrets outside the session and reference them by indirect identifiers. Use strict attribute filtering on the SAML consumer so that only necessary user attributes are accepted.

Example: Safe SAML session setup with filtered attributes

// start/boot/saml.js
const { saml } = require('@ioc:Adonis/Addons/Saml')

class SamlBoot {
  async start() {
    const consumer = saml.createConsumer({
      entryPoint: 'https://idp.example.com/sso',
      issuer: 'adonis-app',
      callbackUrl: 'https://app.example.com/saml/acs',
      wantAssertionsSigned: true,
      forceAuthn: false,
      skipRequestCompression: false,
      acceptedClockSkewMs: -1,
      validateInResponseTo: true,
      // Only request required attributes
      requestedAttributes: [
        { name: 'email', friendlyName: 'Email', nameFormat: 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri' },
        { name: 'nameId', friendlyName: 'NameID', nameFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress' }
      ],
      // Optional: transform SAML attributes before session write
      transformInResponse: (profile) => ({
        email: profile.getAttribute('email'),
        nameId: profile.getAttribute('nameId')
        // Do NOT include API keys or secrets here
      })
    })

    // In a controller
    async handleLogin({ auth, response }) {
      const samlResponse = this.request.input('SAMLResponse')
      const profile = await consumer.consume(samlResponse)
      if (!profile) {
        return response.badRequest('Invalid SAML response')
      }

      // Create or retrieve local user by email, then start a session
      let user = await User.findBy('email', profile.email)
      if (!user) {
        user = await User.create({ email: profile.email, name: profile.nameId })
      }

      // Store only a user identifier in the session, not API keys
      await auth.use('web').login(user, { remember: false })
      return response.redirect('/dashboard')
    }
  }
}

module.exports = SamlBoot

Example: Using environment-based API keys outside the session

// services/thirdPartyApi.js
const Env = use('Env')

class ThirdPartyApi {
  call(endpoint, payload) {
    const apiKey = Env.get('THIRD_PARTY_API_KEY')
    // Use the key as a bearer token or header, not stored in session
    return fetch(`https://api.example.com/${endpoint}`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload)
    })
  }
}

module.exports = ThirdPartyApi

Example: Restricting debug and error exposure

// start/hooks.js
const use = require('@ioc:Adonis/Core/Use')

const forbiddenHeaders = ['authorization', 'x-api-key']

function sanitizeResponse(error, { response }) {
  if (error && error.stack) {
    // Avoid exposing internal paths or keys in production
    response.status(error.status || 500)
    response.send({ error: 'Internal service error' })
  }
}

module.exports = {
  exception: {
    handler: async (error, { response, request }) => {
      // Generic messages for unexpected errors
      if (error.name === 'RuntimeError') {
        response.status(500).send({ error: 'An unexpected error occurred' })
      } else {
        // Forward to default handler for known Adonis errors
        return sanitizeResponse(error, { response })
      }
    }
  },
  request: {
    before: [({ request }) => {
      // Ensure sensitive headers are not logged
      forbiddenHeaders.forEach((h) => {
        request.headers.delete(h)
      })
    }]
  }
}

middleBrick checks

Use the CLI to validate these practices: middlebrick scan https://your-adonis-api.example.com. The scan evaluates whether API keys appear in session data, whether SAML responses include unexpected attributes, and whether error responses expose sensitive information. Findings are mapped to OWASP API Top 10 and include prioritized remediation guidance.

Frequently Asked Questions

Can middleBrick detect API key exposure in SAML-based AdonisJS apps?
Yes. middleBrick scans the unauthenticated attack surface of an endpoint and checks for API keys in session data, logs, and URL parameters, providing specific findings and remediation guidance.
Does middleBrick fix API key leaks in AdonisJS?
No. middleBrick detects and reports issues with remediation guidance. It does not modify code, block requests, or alter runtime behavior.