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.
1.5.2
Patch Changes
-
#381
74bbf60Thanks @ofri-peretz! - Load rule modules on demand instead of at plugin load.Every plugin barrel used to
requireall 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./oxlintsub-export is the same plugin object it always was.eslint-plugin-jwtandeslint-plugin-vercel-ai-securityalso re-export their rule objects as named top-level exports, which cannot be deferred — those two keep loading eagerly. -
#381
74bbf60Thanks @ofri-peretz! - Declare what we support, load only what we usetslibis 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 twelverequire("tslib")calls could resolve. The shipped JavaScript now inlines the TypeScript helpers instead (--importHelpers falseon the emit pass that already re-writes it), costing ~9.5 kB in devkit. Zerotslibrequires remain anywhere; verified by installing every plugin with notslibin the tree and loading all 26 with every rule intact.eslint-plugin-import-nexthad a phantom dependency. Its rulesrequire("typescript")at module load, but it was declared in neitherdependenciesnorpeerDependencies— 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.typescriptis 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
peerDependenciesMetawith no matchingpeerDependenciesentry, and npm ignores meta for a package that is not declared a peer — verified by installingeslint-plugin-express-securityand watching nothing install and nothing warn.eslint-plugin-jwtappeared to support six JWT libraries and formally supported none. All 23 are now real optional peers, matching the conventionpg,mongodb,prismaand the other nine already followed:plugin technologies 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
requirewith 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 whyeslint-plugin-import-nextlegitimately declaresoxc-resolverthat devkit lazily loads. -
#335
47cde07Thanks @ofri-peretz! - Fix the./oxlintsubpath export, which pointed atsrc/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'sjsPlugins. 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
47cde07Thanks @ofri-peretz! - Fix SDK peer declarations that npm silently ignoredTwelve plugins listed their target SDKs under
peerDependenciesMetawith{"optional": true}but never declared them inpeerDependencies. npm drops anypeerDependenciesMetaentry that has no matchingpeerDependencieskey, 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-pgandeslint-plugin-mongodb-securityalready use — a supported major range inpeerDependencies,optional: trueinpeerDependenciesMeta:Plugin SDK Range express-securityexpress^4.0.0 || ^5.0.0helmet^6.0.0 || ^7.0.0 || ^8.0.0cors^2.0.0csurf^1.0.0express-rate-limit^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0jwtjsonwebtoken^8.0.0 || ^9.0.0@nestjs/jwt^9.0.0 || ^10.0.0 || ^11.0.0express-jwt^7.0.0 || ^8.0.0jose^4.0.0 || ^5.0.0 || ^6.0.0jwks-rsa^3.0.0 || ^4.0.0jwt-decode^3.0.0 || ^4.0.0lambda-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.0maintainabilitytypescript>=4.8.4nestjs-security@nestjs/common^9.0.0 || ^10.0.0 || ^11.0.0@nestjs/throttler^4.0.0 || ^5.0.0 || ^6.0.0class-validator^0.14.0 || ^0.15.0class-transformer^0.5.0react-featurestypescript>=4.8.4vercel-ai-securityai^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0jwt-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.0anthropic-security@anthropic-ai/sdk>=0.1.0 <1.0.0@anthropic-ai/claude-agent-sdk>=0.1.0 <1.0.0gemini-security@google/genai^1.0.0 || ^2.0.0mcp-sdk-security@modelcontextprotocol/sdk^1.0.0Ranges 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-transformerand@aws-sdk/client-lambdahave only ever shipped one usable major. Theairange spans v4 becauserequire-max-stepsdeliberately accepts both the v4maxStepsoption and the v5+stopWhenform. The twotypescriptentries reuse the>=4.8.4bound@interlace/eslint-devkitalready 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.0rather than a caret, because^0.115.0resolves 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.tsnow locks the invariant across every workspace package: apeerDependenciesMetakey with nopeerDependenciestwin 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
86baa02Thanks @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
4a89231Thanks @ofri-peretz! - Catch AI output interpolated into SQL, and acceptmax_output_tokensno-unsafe-output-handlingnow 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.textwhile the destructured source readstext. It also drops a false positive on SQL whose literal text merely contained a pattern word (e.g. agenerated_reportstable name).require-max-tokensnow acceptsmax_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
b2e887bThanks @ofri-peretz! - Document the options the rules actually acceptTen 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-schemaandbrowser-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
1b8c0dfThanks @ofri-peretz! - Fix SDK peer declarations that npm silently ignoredSeven plugins listed their target SDKs under
peerDependenciesMetawith{"optional": true}but never declared them inpeerDependencies. npm drops anypeerDependenciesMetaentry that has no matchingpeerDependencieskey, 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-pgandeslint-plugin-mongodb-securityalready use — a supported major range inpeerDependencies,optional: trueinpeerDependenciesMeta:Plugin SDK Range express-securityexpress^4.0.0 || ^5.0.0helmet^6.0.0 || ^7.0.0 || ^8.0.0cors^2.0.0csurf^1.0.0express-rate-limit^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0jwtjsonwebtoken^8.0.0 || ^9.0.0@nestjs/jwt^9.0.0 || ^10.0.0 || ^11.0.0express-jwt^7.0.0 || ^8.0.0jose^4.0.0 || ^5.0.0 || ^6.0.0jwks-rsa^3.0.0 || ^4.0.0jwt-decode^3.0.0 || ^4.0.0lambda-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.0maintainabilitytypescript>=4.8.4nestjs-security@nestjs/common^9.0.0 || ^10.0.0 || ^11.0.0@nestjs/throttler^4.0.0 || ^5.0.0 || ^6.0.0class-validator^0.14.0 || ^0.15.0class-transformer^0.5.0react-featurestypescript>=4.8.4vercel-ai-securityai^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0Ranges 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-transformerand@aws-sdk/client-lambdahave only ever shipped one usable major. Theairange spans v4 becauserequire-max-stepsdeliberately accepts both the v4maxStepsoption and the v5+stopWhenform. The twotypescriptentries reuse the>=4.8.4bound@interlace/eslint-devkitalready 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
0bd0626Thanks @ofri-peretz! - Don't read a computed property key as if it were a property name.getStaticPropNametook a key node and returnedkey.namefor any Identifier, without checking whether the property was computed. In{ [instructions]: value }the key node is an Identifier calledinstructions— 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
Propertynode and returnsnullfor 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
keyandoriginKey. 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
dc25c81Thanks @ofri-peretz! - Re-publish every package so npm carries the optimised artifactNo source changed. This is a no-op patch whose entire purpose is to ship the artifact the current build already produces.
Manifests.
scriptsanddevDependenciesare now stripped from every publishedpackage.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.tstree:package published rebuilt saving eslint-plugin-react-features547 kB 320 kB −227 kB eslint-plugin-secure-coding653 kB 477 kB −176 kB eslint-plugin-conventions241 kB 116 kB −125 kB eslint-plugin-browser-security380 kB 291 kB −89 kB eslint-plugin-maintainability178 kB 116 kB −62 kB eslint-plugin-react-a11y232 kB 173 kB −59 kB eslint-plugin-reliability148 kB 90 kB −58 kB eslint-plugin-vercel-ai-security187 kB 130 kB −57 kB eslint-plugin-operability90 kB 43 kB −47 kB eslint-plugin-jwt140 kB 95 kB −45 kB eslint-plugin-modularity98 kB 58 kB −40 kB eslint-plugin-nestjs-security122 kB 86 kB −36 kB eslint-plugin-sqlite-security54 kB 20 kB −34 kB eslint-plugin-sequelize-security54 kB 21 kB −34 kB eslint-plugin-prisma-security52 kB 19 kB −33 kB eslint-plugin-mysql-security52 kB 19 kB −33 kB eslint-plugin-typeorm-security52 kB 19 kB −33 kB eslint-plugin-drizzle-security52 kB 19 kB −33 kB eslint-plugin-knex-security51 kB 19 kB −32 kB eslint-plugin-modernization45 kB 38 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.tsfails the build ifscriptsordevDependenciesever reappear in a published manifest, so the strip cannot silently regress.The dependency ranges did not need updating: every plugin pins
@interlace/eslint-devkitwith 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 notypescriptin the tree. -
Updated dependencies [
dc25c81]:- @interlace/eslint-devkit@1.6.1
1.4.0
Minor Changes
-
#299
608defbThanks @ofri-peretz! - Detect the AI SDK v7instructionsoption, not just the deprecatedsystem.AI SDK v7 renamed the system-prompt option to
instructionsand markssystemas@deprecated Use 'instructions' insteadin its own type definitions. Four rules matched the property namesystemliterally, so on any code written against current AI SDK docs they reported nothing at all:no-dynamic-system-promptrequire-validated-prompt(itsunsafeSystemPromptbranch)require-rag-content-validationno-sensitive-in-prompt
All four now accept either spelling via a shared
SYSTEM_PROMPT_PROPSset, sosystemkeeps working for pre-v7 code andinstructionsis covered going forward.The same pass closed a second silent miss in those rules: a quoted key (
{ "instructions": … }) parses to a stringLiteral, not anIdentifier, and three of the four rules read onlyIdentifierkeys — so putting quotes round the key was enough to stop them firing. Key extraction now goes through a sharedgetStaticPropNamehelper. Three fixtures that recorded this as expected behaviour (one labelled "documented FN: only Identifier keys are matched") moved fromvalidtoinvalid, since a rule that stops firing on formatting is a miss, not a design decision. Computed keys ({ [k]: … }) still returnnull— there the name genuinely isn't statically known.This was found the hard way. Scanning the
nuxt-ui-templates/chattemplate, a system prompt interpolating the signed-in user's name straight intoinstructions: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 theinstructionsspelling 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
659f6dcThanks @ofri-peretz! - Rewritedescriptionandkeywordson 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-nextclaimed "100x faster no-cycle detection". No 100x measurement exists:CLAIMS.mdrecords 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-codingclaimed 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") andeslint-plugin-react-a11y("37 rules") hard-coded rule counts that had drifted from reality. Counts are generated intointerlace-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-nandeslint-plugin-importall carry theeslint/eslintplugin/eslint-plugintrio — six of our packages were missingeslintplugin, and every one now carries all three plusstatic-analysis,lintingandcode-quality. Security plugins addsast,appsecandvulnerability;node-securityandsecure-codingalso carrynodesecurity, the exact keywordeslint-plugin-securityranks on. Each plugin gained the CWE identifiers and attack names for what it detects (cwe-78command injection,cwe-22path traversal,cwe-89SQL injection,cwe-79XSS,cwe-347JWT algorithm confusion,cwe-352CSRF,cwe-943NoSQL injection), andnode-securitygained 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
d1ad332Thanks @ofri-peretz! - Accept AI SDK v5+ idioms:stopWhen(e.g.stopWhen: stepCountIs(5)) now satisfies require-max-steps, andmaxOutputTokens(v5 rename ofmaxTokens) satisfies require-max-tokens — fixing false positives on v5/v7 code.
1.3.8
Patch Changes
-
#269
7028fe2Thanks @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
d67e395Thanks @ofri-peretz! - Fix Codecov badge showing "unknown" — switch from flag to component URL format
1.3.6
Patch Changes
-
#144
8843ce7Thanks @ofri-peretz! - fix: ILB-Wild FP reduction + doc examples + doc-test-alignment scanner fixesno-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.ofcalls in thealloc/Arraypattern 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-checklambda-security/no-overly-permissive-iam-policynode-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-alignmentscanner fixes- Accept both
## ❌and### ❌headings (docs use H3 under an H2## Examplessection; was only finding H2) - Slice from end-of-line rather than end-of-regex-match (prevents
## ❌ Incorrect Codefrom leaving a partial heading in the parsed section)
Result:
ilb:doc-test-alignment→ 206 ok, 0 doc has no ❌ examples (was 165 missing). - Skip loop-allocation reporting when the first argument is a numeric literal (e.g.
-
#143
213cde1Thanks @ofri-peretz! - fix(no-missing-null-checks): eliminate 53 false positives via three new narrowing patternsRules that were recognized as null guards are now correctly identified as safe:
- Truthy if guard —
if (obj) { obj.prop }— direct truthy check proves non-null. Also covers chains:if (response)protectsresponse.data.items. - Short-circuit AND —
obj && obj.prop— right side of&&only runs when left is truthy. - Ternary consequent —
obj ? obj.prop : fallback— truthy test guards the consequent.
Also: bumped
beforeAlltimeout 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. - Truthy if guard —
-
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.0ai(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 coveragestreamText- Full coverage with abort signalgenerateObject- Full coveragestreamObject- Full coverage with abort signaltool()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.