HIGH token leakagefeathersjsdynamodb

Token Leakage in Feathersjs with Dynamodb

Token Leakage in Feathersjs with Dynamodb — how this specific combination creates or exposes the vulnerability

Token leakage in a Feathersjs service backed by DynamoDB typically occurs when authentication tokens or session identifiers are unintentionally exposed through API responses, logs, or error messages. This risk is amplified by misconfigured service hooks, improper data serialization, and the way Feathersjs merges query parameters with DynamoDB request attributes.

Feathersjs uses hooks to augment request parameters. If a hook injects an access token or internal identifier into the params object and that object is later passed directly to DynamoDB operations without scrubbing, sensitive values can be reflected in responses or logs. For example, a hook that adds params.token to be used for audit trails might inadvertently allow that token to be returned in a find or get response if the service maps DynamoDB attribute names too closely to user-facing fields.

DynamoDB-specific leakage vectors include the use of attribute names that mirror token-related concepts (e.g., access_token, session_id) and the inclusion of sensitive values in FilterExpression or ProjectionExpression that are echoed back in errors. Misconfigured CORS or service discovery can also cause tokens to appear in client-side JavaScript when responses include DynamoDB metadata fields such as ConsumedCapacity or unmarshaled attribute values that were not intended for the client.

Another common pattern is using DynamoDB UpdateItem with an update expression that references a token value from the request body. If the update expression is built by concatenating user input without strict validation, the resulting response may include the updated token attribute, especially when ReturnValues-style responses are simulated in the application layer. This can expose refresh tokens or session identifiers to unauthorized callers.

To detect these patterns, middleBrick runs an unauthenticated scan against the Feathersjs endpoint, exercising 12 security checks in parallel. One of these checks focuses on unsafe consumption of parameters and data exposure, flagging responses that include credential-like values such as tokens, API keys, or session identifiers. The scan also cross-references OpenAPI/Swagger definitions with runtime findings to highlight mismatches between declared responses and actual output, helping to identify inadvertent token reflection.

Dynamodb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on strict parameter sanitization, avoiding reflection of sensitive values, and careful construction of DynamoDB expressions. Below are concrete, working examples for a Feathersjs service using the AWS SDK for DynamoDB.

1. Exclude tokens from params before DynamoDB operations

Ensure hooks remove or rename sensitive fields before they reach DynamoDB. Use a custom hook to strip token fields from params and avoid mapping them to DynamoDB attribute names.

// src/hooks/remove-tokens.js
module.exports = function () {
  return async context => {
    const { params } = context;
    // Remove token fields that should never reach DynamoDB
    delete params.token;
    delete params.refreshToken;
    delete params.sessionId;
    // Optionally move them to a secure location for server-side use
    const secure = { token: params.token };
    delete params.token;
    context.params.secure = secure;
    return context;
  };
};

2. Safe DynamoDB Find with Projection that omits sensitive attributes

Use ProjectionExpression to return only intended fields, avoiding accidental exposure of token attributes stored in DynamoDB.

// src/services/users/users.service.js
const { DynamoDBDocumentClient, ScanCommand } = require('@aws-sdk/lib-dynamodb');
const ddbDocClient = DynamoDBDocumentClient.from(new DynamoDBDocumentClient());

module.exports = {
  async find(params) {
    const command = new ScanCommand({
      TableName: process.env.USERS_TABLE,
      ProjectionExpression: 'userId, email, createdAt', // exclude token fields
      FilterExpression: 'userId = :uid',
      ExpressionAttributeValues: {
        ':uid': params.query.userId || params.authentication.payload.sub
      }
    });
    const { Items } = await ddbDocClient.send(command);
    return Items.map(item => ({
      userId: item.userId,
      email: item.email,
      createdAt: item.createdAt
      // do not map item.access_token or item.session_id
    }));
  }
};

3. UpdateItem without echoing token values in response

When updating user credentials, avoid returning updated token attributes by controlling ReturnValues behavior on the server side and not exposing DynamoDB metadata to the client.

// src/services/auth/auth.service.js
const { DynamoDBDocumentClient, UpdateCommand } = require('@aws-sdk/lib-dynamodb');
const ddbDocClient = DynamoDBDocumentClient.from(new DynamoDBDocumentClient());

module.exports.updateToken = async function (id, tokenValue) {
  const command = new UpdateCommand({
    TableName: process.env.AUTH_TABLE,
    Key: { userId: id },
    UpdateExpression: 'SET access_token = :token',
    ExpressionAttributeValues: {
      ':token': tokenValue
    },
    // Avoid returning updated attributes; handle server-side only
    ReturnValues: 'NONE'
  });
  await ddbDocClient.send(command);
  return { status: 'ok' };
};

4. Validate and limit query expression inputs to prevent injection of token fields

When building expressions dynamically, validate field names and values to ensure no token-related data is reflected back. Use allowlists for projection fields and avoid concatenating raw user input.

// src/hooks/validate-projection.js
module.exports = function () {
  return async context => {
    const allowedFields = new Set(['userId', 'email', 'name', 'role']);
    const requested = (context.params.query.$select || '').split(',').map(s => s.trim());
    const safe = requested.filter(f => allowedFields.has(f));
    if (safe.length === 0) {
      context.params.query.$select = 'userId,email';
    } else {
      context.params.query.$select = safe.join(',');
    }
    return context;
  };
};

5. Configure CORS and error formatting to prevent token leakage in client responses

Ensure CORS does not expose headers that may contain tokens and that error messages are generic, avoiding stack traces that include token values.

// src/app.js
const app = require('feathers')();
const cors = require('@koa/cors');

app.use(cors({
  origin: process.env.FRONTEND_ORIGIN,
  credentials: true,
  exposedHeaders: [] // do not expose DynamoDB metadata or token headers
}));

app.configure(require('@feathersjs/errors').configure({
  errors: {
    // Ensure errors do not include params or internal fields
    stack: false,
    errorCode: (error, stack) => error.code || 500
  }
}));

By combining these patterns—removing tokens from params, projecting only safe fields, avoiding return of updated attributes, validating dynamic expressions, and hardening error/CORS configurations—you reduce the risk of token leakage in a Feathersjs + DynamoDB stack. middleBrick’s scans can verify these controls by checking for data exposure and unsafe consumption findings, and its integration options (CLI, GitHub Action, MCP Server) help embed ongoing checks into development workflows.

Frequently Asked Questions

Can token leakage in Feathersjs with DynamoDB be detected by scanning an unauthenticated endpoint?
Yes. middleBrick scans the unauthenticated attack surface and flags responses that expose token-like values, helping identify leakage without requiring credentials.
Does fixing token leakage require changes to the DynamoDB schema?
Not necessarily. Remediation focuses on parameter handling, projection expressions, and response formatting in Feathersjs services. Schema changes may help but are often unnecessary if tokens are never mapped to client-visible fields.