Skip to main content
interlace
Plugin: vercel-ai-security

Changelog

Release history and version updates for eslint-plugin-vercel-ai-security

Live from GitHub

This changelog is fetched directly from CHANGELOG.md on GitHub and cached for 2 hours.

Live changelogfrom eslint-plugin-vercel-ai-security/CHANGELOG.md, cached for 2 hours.Edit on GitHub

1.5.2

Patch Changes

  • #381 74bbf60 Thanks @ofri-peretz! - Load rule modules on demand instead of at plugin load.

    Every plugin barrel used to require all of its rules the moment ESLint loaded the plugin, whether or not your config enabled them. plugin.rules[id] is only ever read for rules a config turns on, so the rest was parse-and-compile cost for code that never ran.

    The published entry now exposes each rule behind a getter, so a rule module is read the first time something asks for it. Measured on a 7-plugin config with 34 rules enabled: 163 rule modules loaded and 251 ms of plugin load, against 34 modules and 8.5 ms — total ESLint wall time 251 ms → 109 ms. On a preset that enables most of a plugin (node-security/recommended, 25 of 37) it is a wash, 72 ms → 65 ms. It is never slower; the win scales with how many plugins you stack and how few of their rules you use.

    Nothing about the plugin API changes. Object.keys(plugin.rules) still lists every rule without loading any of them, repeated reads return the same object, and the ./oxlint sub-export is the same plugin object it always was.

    eslint-plugin-jwt and eslint-plugin-vercel-ai-security also re-export their rule objects as named top-level exports, which cannot be deferred — those two keep loading eagerly.

  • #381 74bbf60 Thanks @ofri-peretz! - Declare what we support, load only what we use

    tslib is gone from every package. It was a NON-optional peer of @interlace/eslint-devkit, so all 26 plugins declared it as a dependency to satisfy that peer — 124 kB every consumer installed so twelve require("tslib") calls could resolve. The shipped JavaScript now inlines the TypeScript helpers instead (--importHelpers false on the emit pass that already re-writes it), costing ~9.5 kB in devkit. Zero tslib requires remain anywhere; verified by installing every plugin with no tslib in the tree and loading all 26 with every rule intact.

    eslint-plugin-import-next had a phantom dependency. Its rules require("typescript") at module load, but it was declared in neither dependencies nor peerDependencies — it worked only because something else in the tree happened to install it. A clean install crashed the whole plugin, not just the type-aware rules. typescript is now a required peer, which is what the code actually needs.

    23 "technologies we support" declarations did nothing. Seven plugins listed their target libraries in peerDependenciesMeta with no matching peerDependencies entry, and npm ignores meta for a package that is not declared a peer — verified by installing eslint-plugin-express-security and watching nothing install and nothing warn. eslint-plugin-jwt appeared to support six JWT libraries and formally supported none. All 23 are now real optional peers, matching the convention pg, mongodb, prisma and the other nine already followed:

    plugintechnologies now actually declared
    eslint-plugin-jwtjsonwebtoken, @nestjs/jwt, express-jwt, jose, jwks-rsa, jwt-decode
    eslint-plugin-lambda-security@aws-sdk/client-lambda, @middy/core, @middy/http-cors, @middy/http-security-headers, @middy/validator
    eslint-plugin-express-securityexpress, helmet, cors, csurf, express-rate-limit
    eslint-plugin-nestjs-security@nestjs/common, @nestjs/throttler, class-validator, class-transformer
    eslint-plugin-vercel-ai-securityai
    eslint-plugin-maintainability, eslint-plugin-react-featurestypescript

    All optional, so nothing is installed on the consumer’s behalf — the declaration is the supported-technology signal, which is exactly what it was meant to be.

    A new gate compares declared dependencies against what the emitted JavaScript actually loads, in both directions: a require with no declaration (works until someone installs cleanly) and a declaration nothing requires (weight every consumer pays). It understands that a dependency may exist to satisfy an optional peer of another dependency, which is why eslint-plugin-import-next legitimately declares oxc-resolver that devkit lazily loads.

  • #335 47cde07 Thanks @ofri-peretz! - Fix the ./oxlint subpath export, which pointed at src/oxlint.js — a file no build produces. require('<package>/oxlint') threw MODULE_NOT_FOUND on every published package, while every README documented that exact wiring for oxlint's jsPlugins. The export now points at the build output, dist/src/oxlint.js.

    The path was hardcoded in scripts/generate-oxlint-shims.ts, so the generator rewrote any manual correction back to the broken value on the next drift check — fixed there rather than per package.

    This release also carries npm provenance: the affected packages were last published from a workstation, which has no OIDC token to attest with, so the published tarballs had no attestation. Publishing through the release workflow signs them.

  • #335 47cde07 Thanks @ofri-peretz! - Fix SDK peer declarations that npm silently ignored

    Twelve plugins listed their target SDKs under peerDependenciesMeta with {"optional": true} but never declared them in peerDependencies. npm drops any peerDependenciesMeta entry that has no matching peerDependencies key, so the metadata was inert — these packages effectively declared no SDK peer at all. Nothing warned: the failure mode of a dependency you never declared is silence.

    Each SDK now appears in both maps, matching the shape eslint-plugin-pg and eslint-plugin-mongodb-security already use — a supported major range in peerDependencies, optional: true in peerDependenciesMeta:

    PluginSDKRange
    express-securityexpress^4.0.0 || ^5.0.0
    helmet^6.0.0 || ^7.0.0 || ^8.0.0
    cors^2.0.0
    csurf^1.0.0
    express-rate-limit^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
    jwtjsonwebtoken^8.0.0 || ^9.0.0
    @nestjs/jwt^9.0.0 || ^10.0.0 || ^11.0.0
    express-jwt^7.0.0 || ^8.0.0
    jose^4.0.0 || ^5.0.0 || ^6.0.0
    jwks-rsa^3.0.0 || ^4.0.0
    jwt-decode^3.0.0 || ^4.0.0
    lambda-security@aws-sdk/client-lambda^3.0.0
    @middy/core^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    @middy/http-cors^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    @middy/http-security-headers^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    @middy/validator^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    maintainabilitytypescript>=4.8.4
    nestjs-security@nestjs/common^9.0.0 || ^10.0.0 || ^11.0.0
    @nestjs/throttler^4.0.0 || ^5.0.0 || ^6.0.0
    class-validator^0.14.0 || ^0.15.0
    class-transformer^0.5.0
    react-featurestypescript>=4.8.4
    vercel-ai-securityai^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    jwt-securitysame six as jwt(identical ranges)
    openai-securityopenai^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    @openai/agents>=0.1.0 <1.0.0
    anthropic-security@anthropic-ai/sdk>=0.1.0 <1.0.0
    @anthropic-ai/claude-agent-sdk>=0.1.0 <1.0.0
    gemini-security@google/genai^1.0.0 || ^2.0.0
    mcp-sdk-security@modelcontextprotocol/sdk^1.0.0

    Ranges were taken from each SDK's real release history, bounded below by the oldest major whose call shape the rules still match and above by the current major. cors, csurf, class-transformer and @aws-sdk/client-lambda have only ever shipped one usable major. The ai range spans v4 because require-max-steps deliberately accepts both the v4 maxSteps option and the v5+ stopWhen form. The two typescript entries reuse the >=4.8.4 bound @interlace/eslint-devkit already declares, since these are the same type-aware-graceful rules behind the same optional TS program.

    Every range admits the version this repo's __compatibility__ specs are actually tested against, so the declaration cannot drift from what CI proves.

    The four SDKs still on 0.x (@openai/agents, both Anthropic packages) use an explicit >=0.1.0 <1.0.0 rather than a caret, because ^0.115.0 resolves to >=0.115.0 <0.116.0 — a range narrow enough to warn on almost every real install. These rules match on call shape and never import the SDK, so the honest constraint is the pre-1.0 line, not a single minor.

    peer-declaration-integrity.test.ts now locks the invariant across every workspace package: a peerDependenciesMeta key with no peerDependencies twin fails the suite and is named in the diff. This class had already been fixed once, in a commit that never merged — nothing went red in its absence, so the bug came back on four newly published packages. A silent failure needs a lock, not review attention.

    Nothing to migrate. Every entry stays optional, so no install adds a package or emits a warning when the SDK is absent. What changes is that a consumer on an unsupported major now gets a peer warning instead of nothing — which was the point of the metadata in the first place.

  • Updated dependencies [85e57a7, 74bbf60, e5d31ab, 1fb1cad, d1a3d8c]:

    • @interlace/eslint-devkit@1.8.0

1.5.1

Patch Changes

  • #364 86baa02 Thanks @ofri-peretz! - Add the ecosystem and oxlint marks to the README logo row. Each plugin now leads with Interlace -> its ecosystem (node, nestjs, express, react, mongodb, postgresql, mysql, sqlite, prisma, drizzle, knex, typeorm, sequelize, lambda, vercel, jwt) -> oxlint -> ESLint; the generic quality plugins carry the row without an ecosystem mark. README-only change - no rule behaviour is affected. The patch bump is what carries the new README onto npm, which only refreshes a package README on publish.

1.5.0

Minor Changes

  • #262 4a89231 Thanks @ofri-peretz! - Catch AI output interpolated into SQL, and accept max_output_tokens

    no-unsafe-output-handling now walks a template literal's ${...} expressions and the operands of a + chain instead of pattern-matching the whole source text. This closes a false negative where a tracked binding — const { text } = await generateText(...); db.query(`... ${text}`) — was missed even though the eval and innerHTML branches already tracked it. Text matching only ever caught the ${result.text} spelling, because the patterns look for .text while the destructured source reads text. It also drops a false positive on SQL whose literal text merely contained a pattern word (e.g. a generated_reports table name).

    require-max-tokens now accepts max_output_tokens. It already accepted the snake_case spelling of the v4 name (max_tokens) but not of the v5 one, so a call bounded through a provider-shaped config object was still reported.

Patch Changes

  • #359 b2e887b Thanks @ofri-peretz! - Document the options the rules actually accept

    Ten option names appeared in rule docs but not in the rules' schemas. Because every schema sets additionalProperties: false, copying one out of the docs did not fail quietly — it aborted the whole lint run:

    Key "rules": Key "vercel-ai-security/no-hardcoded-api-keys":
      Value {"keyPatterns":[...]} should NOT have additional properties.
      Unexpected property "keyPatterns". Expected properties: "apiKeyPatterns".

    Six of the seven affected tables were fictional end to end — not one documented option existed. Affected rules: no-hardcoded-api-keys, no-unsafe-output-handling, require-abort-signal, require-max-steps, require-max-tokens, require-tool-schema and browser-security/no-sensitive-localstorage.

    Three "Mitigation: configure X" notes pointed at knobs that are hardcoded and were never configurable; they now say so instead of promising a fix that cannot be applied.

    No rule behaviour changes — this is documentation catching up to the schemas.

  • #358 1b8c0df Thanks @ofri-peretz! - Fix SDK peer declarations that npm silently ignored

    Seven plugins listed their target SDKs under peerDependenciesMeta with {"optional": true} but never declared them in peerDependencies. npm drops any peerDependenciesMeta entry that has no matching peerDependencies key, so the metadata was inert — these packages effectively declared no SDK peer at all. Nothing warned: the failure mode of a dependency you never declared is silence.

    Each SDK now appears in both maps, matching the shape eslint-plugin-pg and eslint-plugin-mongodb-security already use — a supported major range in peerDependencies, optional: true in peerDependenciesMeta:

    PluginSDKRange
    express-securityexpress^4.0.0 || ^5.0.0
    helmet^6.0.0 || ^7.0.0 || ^8.0.0
    cors^2.0.0
    csurf^1.0.0
    express-rate-limit^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
    jwtjsonwebtoken^8.0.0 || ^9.0.0
    @nestjs/jwt^9.0.0 || ^10.0.0 || ^11.0.0
    express-jwt^7.0.0 || ^8.0.0
    jose^4.0.0 || ^5.0.0 || ^6.0.0
    jwks-rsa^3.0.0 || ^4.0.0
    jwt-decode^3.0.0 || ^4.0.0
    lambda-security@aws-sdk/client-lambda^3.0.0
    @middy/core^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    @middy/http-cors^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    @middy/http-security-headers^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    @middy/validator^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
    maintainabilitytypescript>=4.8.4
    nestjs-security@nestjs/common^9.0.0 || ^10.0.0 || ^11.0.0
    @nestjs/throttler^4.0.0 || ^5.0.0 || ^6.0.0
    class-validator^0.14.0 || ^0.15.0
    class-transformer^0.5.0
    react-featurestypescript>=4.8.4
    vercel-ai-securityai^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0

    Ranges were taken from each SDK's real release history, bounded below by the oldest major whose call shape the rules still match and above by the current major. cors, csurf, class-transformer and @aws-sdk/client-lambda have only ever shipped one usable major. The ai range spans v4 because require-max-steps deliberately accepts both the v4 maxSteps option and the v5+ stopWhen form. The two typescript entries reuse the >=4.8.4 bound @interlace/eslint-devkit already declares, since these are the same type-aware-graceful rules behind the same optional TS program.

    Every range admits the version this repo's __compatibility__ specs are actually tested against, so the declaration cannot drift from what CI proves.

    Nothing to migrate. Every entry stays optional, so no install adds a package or emits a warning when the SDK is absent. What changes is that a consumer on an unsupported major now gets a peer warning instead of nothing — which was the point of the metadata in the first place.

  • Updated dependencies [e8e9ee6]:

    • @interlace/eslint-devkit@1.7.0

1.4.2

Patch Changes

  • #340 0bd0626 Thanks @ofri-peretz! - Don't read a computed property key as if it were a property name.

    getStaticPropName took a key node and returned key.name for any Identifier, without checking whether the property was computed. In { [instructions]: value } the key node is an Identifier called instructions — but it's a variable reference, and the property actually being set is whatever that variable holds. All four rules that resolve the system prompt (no-dynamic-system-prompt, require-validated-prompt, require-rag-content-validation, no-sensitive-in-prompt) therefore treated an arbitrary property as the system prompt.

    The helper now takes the Property node and returns null for computed keys.

    This only misfires when the variable is named exactly like the property, which is why the existing computed-key fixtures missed it — they used variables named key and originKey. The new regression test uses the collision case.

    Found while fixing the identical bug in eslint-plugin-nestjs-security; the same helper shape had been copied between the two plugins.

1.4.1

Patch Changes

  • #338 dc25c81 Thanks @ofri-peretz! - Re-publish every package so npm carries the optimised artifact

    No source changed. This is a no-op patch whose entire purpose is to ship the artifact the current build already produces.

    Manifests. scripts and devDependencies are now stripped from every published package.json. Neither can do anything in a consumer’s node_modules — npm never runs one and never installs the other — but they shipped in all 27 manifests, cluttered the npm page, and were read by SCA tools scanning installed manifests. No package declares a lifecycle hook, so nothing observable changes. Every published package is bumped so this applies uniformly rather than to a subset.

    Tarballs. 20 packages were last published before the build pipeline changed and still ship AGENTS.md, CHANGELOG.md, JSDoc in the emitted .js, and the full generated .d.ts tree:

    packagepublishedrebuiltsaving
    eslint-plugin-react-features547 kB320 kB−227 kB
    eslint-plugin-secure-coding653 kB477 kB−176 kB
    eslint-plugin-conventions241 kB116 kB−125 kB
    eslint-plugin-browser-security380 kB291 kB−89 kB
    eslint-plugin-maintainability178 kB116 kB−62 kB
    eslint-plugin-react-a11y232 kB173 kB−59 kB
    eslint-plugin-reliability148 kB90 kB−58 kB
    eslint-plugin-vercel-ai-security187 kB130 kB−57 kB
    eslint-plugin-operability90 kB43 kB−47 kB
    eslint-plugin-jwt140 kB95 kB−45 kB
    eslint-plugin-modularity98 kB58 kB−40 kB
    eslint-plugin-nestjs-security122 kB86 kB−36 kB
    eslint-plugin-sqlite-security54 kB20 kB−34 kB
    eslint-plugin-sequelize-security54 kB21 kB−34 kB
    eslint-plugin-prisma-security52 kB19 kB−33 kB
    eslint-plugin-mysql-security52 kB19 kB−33 kB
    eslint-plugin-typeorm-security52 kB19 kB−33 kB
    eslint-plugin-drizzle-security52 kB19 kB−33 kB
    eslint-plugin-knex-security51 kB19 kB−32 kB
    eslint-plugin-modernization45 kB38 kB−7 kB

    Those 20 go from 3428 kB to 2169 kB — −36.7%. The remaining 7 were released after the pipeline change and only gain the manifest strip.

    A new check in scripts/check-published-artifacts.ts fails the build if scripts or devDependencies ever reappear in a published manifest, so the strip cannot silently regress.

    The dependency ranges did not need updating: every plugin pins @interlace/eslint-devkit with a caret that 1.6.0 satisfies, verified by a clean install of an unchanged plugin resolving devkit 1.6.0 with zero dependencies and no typescript in the tree.

  • Updated dependencies [dc25c81]:

    • @interlace/eslint-devkit@1.6.1

1.4.0

Minor Changes

  • #299 608defb Thanks @ofri-peretz! - Detect the AI SDK v7 instructions option, not just the deprecated system.

    AI SDK v7 renamed the system-prompt option to instructions and marks system as @deprecated Use 'instructions' instead in its own type definitions. Four rules matched the property name system literally, so on any code written against current AI SDK docs they reported nothing at all:

    • no-dynamic-system-prompt
    • require-validated-prompt (its unsafeSystemPrompt branch)
    • require-rag-content-validation
    • no-sensitive-in-prompt

    All four now accept either spelling via a shared SYSTEM_PROMPT_PROPS set, so system keeps working for pre-v7 code and instructions is covered going forward.

    The same pass closed a second silent miss in those rules: a quoted key ({ "instructions": … }) parses to a string Literal, not an Identifier, and three of the four rules read only Identifier keys — so putting quotes round the key was enough to stop them firing. Key extraction now goes through a shared getStaticPropName helper. Three fixtures that recorded this as expected behaviour (one labelled "documented FN: only Identifier keys are matched") moved from valid to invalid, since a rule that stops firing on formatting is a miss, not a design decision. Computed keys ({ [k]: … }) still return null — there the name genuinely isn't statically known.

    This was found the hard way. Scanning the nuxt-ui-templates/chat template, a system prompt interpolating the signed-in user's name straight into instructions: went unreported — the finding was spotted by reading the file, not by the linter that exists to catch it. Each of the four rules now carries a regression test that fails if the instructions spelling is dropped again, and one of them uses the exact template-literal shape from that file.

Patch Changes

  • Updated dependencies [09d2951]:
    • @interlace/eslint-devkit@1.4.4

1.3.10

Patch Changes

  • #294 659f6dc Thanks @ofri-peretz! - Rewrite description and keywords on every published package for npm search discovery. npm ranks on name, description, and keywords, and the registry only picks up these fields at publish — so this is metadata-only and takes effect for each package on its next release.

    Descriptions now lead with the search phrase. Every one starts ESLint plugin for <the thing you'd search> instead of a brand-first or category-first framing, and names the concrete vulnerabilities the plugin actually detects. Three were corrected while doing so:

    • eslint-plugin-import-next claimed "100x faster no-cycle detection". No 100x measurement exists: CLAIMS.md records 3.1x end-to-end (8x in pure rule execution) on a 5,483-file React codebase, and the highest number in any benchmark result is 54.9x on the synthetic corpus. The description now states the real-codebase figure.
    • eslint-plugin-secure-coding claimed SQL injection, XSS and CSRF coverage — none of which are its rules. It now names what it does detect: LDAP, XPath, XXE, GraphQL and template injection, unsafe deserialization, ReDoS, missing authentication, and PII in logs.
    • eslint-plugin-secure-coding ("89 rules") and eslint-plugin-react-a11y ("37 rules") hard-coded rule counts that had drifted from reality. Counts are generated into interlace-numbers.json; hand-typed copies are removed rather than corrected.

    Keywords now match the vocabulary of the plugins that rank. eslint-plugin-security, eslint-plugin-jsx-a11y, eslint-plugin-n and eslint-plugin-import all carry the eslint / eslintplugin / eslint-plugin trio — six of our packages were missing eslintplugin, and every one now carries all three plus static-analysis, linting and code-quality. Security plugins add sast, appsec and vulnerability; node-security and secure-coding also carry nodesecurity, the exact keyword eslint-plugin-security ranks on. Each plugin gained the CWE identifiers and attack names for what it detects (cwe-78 command injection, cwe-22 path traversal, cwe-89 SQL injection, cwe-79 XSS, cwe-347 JWT algorithm confusion, cwe-352 CSRF, cwe-943 NoSQL injection), and node-security gained the crypto vocabulary it had been missing entirely despite absorbing the crypto rule set (crypto, cryptography, weak-hash, md5, sha1, timing-attack).

    No rule behavior, exports, or configuration changes.

  • Updated dependencies [e1cdf83, 659f6dc]:

    • @interlace/eslint-devkit@1.4.3

1.3.9

Patch Changes

  • #277 d1ad332 Thanks @ofri-peretz! - Accept AI SDK v5+ idioms: stopWhen (e.g. stopWhen: stepCountIs(5)) now satisfies require-max-steps, and maxOutputTokens (v5 rename of maxTokens) satisfies require-max-tokens — fixing false positives on v5/v7 code.

1.3.8

Patch Changes

  • #269 7028fe2 Thanks @ofri-peretz! - docs: dual-logo README header (Interlace mark + ESLint mark side by side) and closing Interlace footer — refreshes the README rendered on npmjs.com. No runtime changes.

  • Updated dependencies [7028fe2]:

    • @interlace/eslint-devkit@1.4.2

1.3.7

Patch Changes

  • #252 d67e395 Thanks @ofri-peretz! - Fix Codecov badge showing "unknown" — switch from flag to component URL format

1.3.6

Patch Changes

  • #144 8843ce7 Thanks @ofri-peretz! - fix: ILB-Wild FP reduction + doc examples + doc-test-alignment scanner fixes

    no-unlimited-resource-allocation — FP reduction (430 Edge FPs)

    • Skip loop-allocation reporting when the first argument is a numeric literal (e.g. Buffer.alloc(1024) inside a loop is statically bounded, not a risk)
    • Skip Array.isArray, Array.from, Array.of calls in the alloc/Array pattern check (these don't allocate unbounded memory)

    no-hardcoded-credentials — FP reduction (~280 Edge FPs)

    • Extended test-file skip to cover .fixture., .mock., __mocks__/, /tests/, /fixtures/, /mocks/ paths
    • Skip string literals that are fallback values in process.env.X || 'fallback' expressions — the secret lives in the environment, the string is only a dev-mode default

    Doc examples — 4 rules now have ❌ Incorrect examples

    • lambda-security/no-missing-authorization-check
    • lambda-security/no-overly-permissive-iam-policy
    • node-security/prefer-native-crypto (renamed non-standard ### ❌ Third-Party (Flagged) to ### ❌ Incorrect)
    • vercel-ai-security/require-tool-confirmation (replaced placeholder with a real tested example)

    ilb-doc-test-alignment scanner fixes

    • Accept both ## ❌ and ### ❌ headings (docs use H3 under an H2 ## Examples section; was only finding H2)
    • Slice from end-of-line rather than end-of-regex-match (prevents ## ❌ Incorrect Code from leaving a partial heading in the parsed section)

    Result: ilb:doc-test-alignment → 206 ok, 0 doc has no ❌ examples (was 165 missing).

  • #143 213cde1 Thanks @ofri-peretz! - fix(no-missing-null-checks): eliminate 53 false positives via three new narrowing patterns

    Rules that were recognized as null guards are now correctly identified as safe:

    1. Truthy if guardif (obj) { obj.prop } — direct truthy check proves non-null. Also covers chains: if (response) protects response.data.items.
    2. Short-circuit ANDobj && obj.prop — right side of && only runs when left is truthy.
    3. Ternary consequentobj ? obj.prop : fallback — truthy test guards the consequent.

    Also: bumped beforeAll timeout to 30 seconds in 7 compatibility test files (__compatibility__/*.spec.ts). Native-addon packages routinely exceed the previous 10-second default on a cold ESM load.

  • Updated dependencies [736a5fe]:

    • @interlace/eslint-devkit@1.4.1

1.3.5 (2026-02-09)

This was a version bump only for eslint-plugin-vercel-ai-security to align it with other projects, there were no code changes.

[1.3.3] - 2026-02-08

Bug Fixes

  • align codecov component IDs with full package names (2831b968)

Documentation

  • fix changelog header format across all packages (c3a15082)

❤️ Thank You

  • Ofri Peretz

[1.3.2] - 2026-02-06

Bug Fixes

  • align codecov component names and update docs components (0a59a86c)

❤️ Thank You

  • Ofri Peretz

[1.3.1] - 2026-02-02

This was a version bump only for eslint-plugin-vercel-ai-security to align it with other projects, there were no code changes.

Changelog

All notable changes to eslint-plugin-vercel-ai-security will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.


[1.0.1] - 2024-12-13

Added

  • Peer Dependencies: Added explicit peer dependency requirements:
    • eslint: ^8.0.0 || ^9.0.0
    • ai (Vercel AI SDK): ^3.0.0 || ^4.0.0 || ^5.0.0

Changed

  • Updated README compatibility section to reflect supported versions

[0.2.0] - 2024-12-13

Added

🔒 New Security Rules (+5)

  • no-system-prompt-leak - Prevent system prompts from being exposed in API responses (LLM07)
  • no-dynamic-system-prompt - Prevent dynamic content in system prompts (ASI01)
  • require-output-filtering - Require filtering of sensitive data in tool output (ASI04)
  • require-audit-logging - Suggest audit logging for AI operations (ASI10)
  • require-rag-content-validation - Validate RAG content before use in prompts (ASI07)

⚙️ New Configuration

  • minimal - Gradual adoption config with only 2 critical rules

📚 Documentation

  • Individual documentation for all 15 rules in /docs/rules/
  • Updated README with complete OWASP coverage tables
  • Options documentation for each rule

Changed

  • Plugin version: 0.1.0 → 0.2.0
  • Total rules: 10 → 15
  • Total tests: 122 → 168
  • OWASP LLM coverage: 5/10 → 6/10
  • OWASP Agentic coverage: 5/10 → 9/10

[0.1.0] - 2024-12-13

Added

🔒 Security Rules (10 Total)

Critical Priority
  • require-validated-prompt - Detect unsafe prompts (CWE-74, OWASP LLM01)
  • no-sensitive-in-prompt - Prevent secrets/PII in prompts (CWE-200, OWASP LLM02)
  • no-hardcoded-api-keys - Detect hardcoded API keys (CWE-798, OWASP ASI03)
  • no-unsafe-output-handling - Prevent unsafe output handling (CWE-94, OWASP LLM05/ASI05)
High Priority
  • require-tool-schema - Ensure tools have Zod inputSchema (CWE-20, OWASP ASI02)
  • require-max-tokens - Require maxTokens limit (CWE-770, OWASP LLM10)
  • require-max-steps - Require maxSteps for multi-step tool calling (CWE-834, OWASP LLM10)
  • require-tool-confirmation - Require confirmation for destructive tools (CWE-862, OWASP ASI09/LLM06)
Medium Priority
  • require-error-handling - Require try-catch for AI calls (CWE-755, OWASP ASI08)
  • require-abort-signal - Require AbortSignal for streaming calls (CWE-404)

⚙️ Configurations

  • recommended - Balanced security (critical rules as errors, high as warnings)
  • strict - Maximum security (all rules enabled)

📊 Coverage

  • 122 tests passing
  • 98.31% line coverage
  • 100% function coverage

📚 Documentation

  • Comprehensive README with AEO optimization
  • AGENTS.md for AI coding assistants
  • Full OWASP LLM Top 10 and OWASP Agentic Top 10 mapping

Supported Functions

  • generateText - Full coverage
  • streamText - Full coverage with abort signal
  • generateObject - Full coverage
  • streamObject - Full coverage with abort signal
  • tool() helper - Schema validation

View on GitHub →

Building secure JavaScript with Interlace? Star the repo to get new rules and CWE coverage as we ship them — or follow the AI-code-security benchmarks behind them.

On this page

No Headings