DEV Community

Cover image for Serverless Security: The AWS Lambda Static Analysis Standard
Ofri Peretz
Ofri Peretz

Posted on • Edited on • Originally published at ofriperetz.dev

Serverless Security: The AWS Lambda Static Analysis Standard

Serverless architectures introduce unique event injection risks. Here is the engineering standard for hardening AWS Lambda through automated static analysis, ensuring safety at the handler level.

Who Is This For?

This plugin is for Node.js teams building serverless applications on AWS:

Framework Description
AWS Lambda Native function handlers
Serverless Framework Most popular serverless deployment tool
AWS SAM CLI AWS-native IaC for Lambda
Middy.js Middleware engine for Lambda (we have specific rules!)

If you deploy functions to Lambda β€” whether via CDK, SAM, Serverless Framework, or raw CloudFormation β€” this plugin catches security issues before they reach production.

Quick Install

npm install --save-dev eslint-plugin-lambda-security
Enter fullscreen mode Exit fullscreen mode

Flat Config

// eslint.config.js
import lambdaSecurity from "eslint-plugin-lambda-security";

export default [lambdaSecurity.configs.recommended];
Enter fullscreen mode Exit fullscreen mode

Rule Overview

Based on the OWASP Serverless Top 10:

Rule OWASP What it catches
no-unvalidated-event-body S1, S10 Injection via event
no-missing-authorization-check S2 No auth in handlers
no-exposed-error-details S3 Stack traces in errors
no-unbounded-batch-processing S4 Large batch DoS
no-overly-permissive-iam-policy S5 * in IAM
no-permissive-cors-response S6 CORS misconfiguration
no-error-swallowing S7 Empty catch blocks
no-secrets-in-env S8 Secrets in env vars
no-user-controlled-requests S9 SSRF
no-env-logging S3 Env logged
no-hardcoded-credentials-sdk S8 AWS creds in code
no-permissive-cors-middy S6 Middy CORS
require-timeout-handling S4 No timeout fallback

Run ESLint

npx eslint .
Enter fullscreen mode Exit fullscreen mode

You'll see output like:

src/handlers/api.ts
  12:5  error  πŸ”’ OWASP-S3 | Error details exposed to client
               Fix: Return generic error message, log details internally

src/handlers/batch.ts
  28:3  error  πŸ”’ OWASP-S4 | Unbounded batch processing detected
               Fix: Add batch size limit: records.slice(0, 100)

src/config/cors.ts
  8:1   error  πŸ”’ OWASP-S6 | Permissive CORS origin '*'
               Fix: Specify allowed origins: ['https://app.example.com']
Enter fullscreen mode Exit fullscreen mode

Quick Wins

Error Handling

// ❌ Dangerous: Exposes stack trace
export const handler = async (event) => {
  try {
    return await processEvent(event);
  } catch (error) {
    return { statusCode: 500, body: JSON.stringify({ error: error.stack }) };
  }
};

// βœ… Safe: Generic error, internal logging
export const handler = async (event) => {
  try {
    return await processEvent(event);
  } catch (error) {
    console.error("Handler error:", error); // Logged to CloudWatch
    return {
      statusCode: 500,
      body: JSON.stringify({ error: "Internal error" }),
    };
  }
};
Enter fullscreen mode Exit fullscreen mode

CORS Configuration

// ❌ Dangerous: Wildcard origin
return {
  statusCode: 200,
  headers: { "Access-Control-Allow-Origin": "*" },
  body: JSON.stringify(data),
};

// βœ… Safe: Explicit origin
return {
  statusCode: 200,
  headers: { "Access-Control-Allow-Origin": "https://app.example.com" },
  body: JSON.stringify(data),
};
Enter fullscreen mode Exit fullscreen mode

Custom Configuration

Add specific rules or customize options:

// eslint.config.js
import lambdaSecurity from "eslint-plugin-lambda-security";

export default [
  lambdaSecurity.configs.recommended,
  {
    rules: {
      // Override severity
      "lambda-security/no-error-swallowing": "warn",

      // Configure with options
      "lambda-security/no-unbounded-batch-processing": [
        "error",
        {
          maxBatchSize: 50,
        },
      ],

      // Disable a rule
      "lambda-security/no-env-logging": "off",
    },
  },
];
Enter fullscreen mode Exit fullscreen mode

Strongly-Typed Options (TypeScript)

The plugin exports types for IDE autocompletion:

// eslint.config.ts
import lambdaSecurity, {
  type RuleOptions,
} from "eslint-plugin-lambda-security";

const batchOptions: RuleOptions["no-unbounded-batch-processing"] = {
  maxBatchSize: 100,
  allowedSources: ["SQS", "Kinesis"],
};

export default [
  lambdaSecurity.configs.recommended,
  {
    rules: {
      "lambda-security/no-unbounded-batch-processing": ["error", batchOptions],
    },
  },
];
Enter fullscreen mode Exit fullscreen mode

Quick Reference

# Install
npm install --save-dev eslint-plugin-lambda-security

# Config (eslint.config.js)
import lambdaSecurity from 'eslint-plugin-lambda-security';
export default [lambdaSecurity.configs.recommended];

# Run
npx eslint .
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ npm: eslint-plugin-lambda-security
πŸ“– OWASP Serverless Mapping

⭐ Star on GitHub


The Interlace ESLint Ecosystem
Interlace is a high-fidelity suite of static code analyzers designed to automate security, performance, and reliability for the modern Node.js stack. With over 330 rules across 18 specialized plugins, it provides 100% coverage for OWASP Top 10, LLM Security, and Database Hardening.

Explore the full Documentation

Β© 2026 Ofri Peretz. All rights reserved.


Build Securely.
I'm Ofri Peretz, a Security Engineering Leader and the architect of the Interlace Ecosystem. I build static analysis standards that automate security and performance for Node.js fleets at scale.

ofriperetz.dev | LinkedIn | GitHub

Top comments (0)