@boring-stack-pkg/eslint-plugin-stripe-webhooks

中文文档
0.1.2发布于 2026/05/25MITTypeScriptESM + CJS近 30 天下载 2237

ESLint plugin enforcing security and correctness rules for Stripe webhooks.

原始使用文档
文档目录12 节
  1. Why
  2. Install
  3. Usage (flat config)
  4. Rules
  5. Examples
  6. handler-must-verify-signature
  7. handler-must-be-idempotent
  8. Security philosophy
  9. Limitations of static analysis
  10. Development
  11. Release
  12. License

eslint-plugin-stripe-webhooks

npm source

ESLint plugin enforcing security and correctness rules for Stripe webhook handlers.

Why

Stripe webhooks have two infamous failure modes:

  1. Unverified payloads. Reading or parsing the request body before *.constructEvent(...) succeeds means an attacker can deliver a webhook-shaped payload to your endpoint and your handler will fire database writes / queue jobs / emails on it. The signature check never gets a chance to reject it.
  2. Non-idempotent and type-blind handling. Stripe redelivers events on transient failures — a handler without a dedupe check on event.id will double-charge, double-email, double-publish. A handler that doesn't branch on event.type will run identical logic for every event kind.

These six rules pin down the patterns that prevent both.

Install

pnpm add -D @boring-stack-pkg/eslint-plugin-stripe-webhooks @typescript-eslint/parser

Usage (flat config)

// eslint.config.mjs
import tsParser from "@typescript-eslint/parser";
import stripeWebhooks from "@boring-stack-pkg/eslint-plugin-stripe-webhooks";

export default [
  {
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      parser: tsParser,
      parserOptions: { ecmaVersion: "latest", sourceType: "module" },
    },
    plugins: { "stripe-webhooks": stripeWebhooks },
    rules: stripeWebhooks.configs.recommended.rules,
  },
];

The recommended preset enables all six rules at "error". Override per-rule via the standard ESLint mechanism.

Rules

RuleTierDescription
handler-must-verify-signatureTIER 1 SECURITYDisallow reading or forwarding the webhook payload before *.constructEvent(...) succeeds.
no-parsed-body-before-verificationSecurityDisallow parsed-body APIs (request.json(), JSON.parse(body), req.body, express.json()) before verification.
require-stripe-signature-headerSecurityRequire the signature passed into constructEvent(...) to come from the Stripe-signature header; forbid hard-coded whsec_* secrets.
handler-must-handle-event-typeCorrectnessStripe event handlers must branch on event.type.
handler-must-be-idempotentCorrectnessWebhook handlers performing side effects must consult event.id for dedupe.
service-must-construct-eventConventionStripe-aware classes with a webhook-named method must also have a verifier method calling constructEvent.

Examples

handler-must-verify-signature

// ❌
export async function POST(request: Request) {
  const body = await request.json();
  const event = stripe.webhooks.constructEvent(body, sig, k);
}

// ✅
export async function POST(request: Request) {
  const body = await request.text();
  const sig = request.headers.get("stripe-signature");
  const event = stripe.webhooks.constructEvent(
    body,
    sig,
    process.env.WEBHOOK_SECRET!,
  );
}

handler-must-be-idempotent

// ❌
export async function handle(event: Stripe.Event) {
  if (event.type === "payment_intent.succeeded") {
    await db.payments.insert({
      /* ... */
    });
  }
}

// ✅
export async function handle(event: Stripe.Event) {
  if (await alreadyProcessed(event.id)) return;
  if (event.type === "payment_intent.succeeded") {
    await db.payments.insert({
      /* ... */
    });
  }
}

For complete per-rule docs and ❌/✅ snippets, see docs/rules/ and the runnable examples/ (Next.js App Router, Express, Elysia/Hono, class-based services).

Security philosophy

These rules are best-effort static analysis. They catch the common mistakes — reading req.body before constructEvent, hard-coded whsec_* secrets, missing event.type branching — but they cannot prove a webhook handler is correct. Specifically, no rule here is sufficient on its own. Pair them with:

  • End-to-end tests against the Stripe CLI webhook simulator.
  • A TIER 1 security review of every webhook entry point at PR time.
  • Centralized verification (see service-must-construct-event) so the verification step lives in one place.

Limitations of static analysis

  • No cross-function dataflow. A body parameter passed into a helper in another file isn't tracked.
  • No type-aware inference. Stripe.Event parameter detection relies on the literal type name + a Stripe import being present in the same file. Generic wrapper types (MyEvent<Stripe.Event>) aren't recognized.
  • Idempotency check detection is heuristic. Helper functions abstracting the dedupe logic must be named per allowedCheckFunctionPatterns. DB unique-constraint-based dedupe isn't visible.
  • Verification by middleware that this rule doesn't recognize will look like "no verification" to the rule.

When in doubt, prefer the explicit, in-handler constructEvent call over a clever abstraction — it's the pattern the rules optimize for.

Development

pnpm install
pnpm test
pnpm typecheck
pnpm build

Release

Tag a v* version locally and push the tag. .github/workflows/release.yml runs pnpm publish --access public --no-git-checks with NPM_TOKEN.

License

MIT.

版本与发布记录

@boring-stack-pkg/eslint-plugin-stripe-webhooks 共发布 2 个版本,首次发布于 2026/05/20;过去 12 个月发布了 2 个版本。

版本发布日期距今
0.1.2latest2026/05/255 个月前
0.1.12026/05/205 个月前

关于 @boring-stack-pkg/eslint-plugin-stripe-webhooks 的常见问题

@boring-stack-pkg/eslint-plugin-stripe-webhooks 是什么?

ESLint plugin enforcing security and correctness rules for Stripe webhooks.

如何安装 @boring-stack-pkg/eslint-plugin-stripe-webhooks?

在项目目录运行 npm install @boring-stack-pkg/eslint-plugin-stripe-webhooks,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@typescript-eslint/parser(>=8.0.0)、eslint(8.57.0 || ^9.0.0)、typescript(>=5.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@boring-stack-pkg/eslint-plugin-stripe-webhooks 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@boring-stack-pkg/eslint-plugin-stripe-webhooks 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@boring-stack-pkg/eslint-plugin-stripe-webhooks 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js ^20.0.0 || ^22.0.0 || >=24.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@boring-stack-pkg/eslint-plugin-stripe-webhooks 可以商用吗?

@boring-stack-pkg/eslint-plugin-stripe-webhooks 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@boring-stack-pkg/eslint-plugin-stripe-webhooks 的下载量有多少?

根据 npm 官方下载统计,@boring-stack-pkg/eslint-plugin-stripe-webhooks 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,237 次,日均约 75 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@boring-stack-pkg/eslint-plugin-stripe-webhooks 还在维护吗?

最新版本 0.1.2 发布于 2026/05/25(5 个月前);至今共发布 2 个版本,其中过去 12 个月发布了 2 个;首次发布于 2026/05/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。