eslint-plugin-vercel-ai-security 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/package.json +5 -20
  2. package/src/index.d.ts +17 -74
  3. package/src/index.js +1 -99
  4. package/src/oxlint.d.ts +17 -20
  5. package/src/oxlint.js +0 -18
  6. package/src/rules/no-dynamic-system-prompt/index.js +0 -22
  7. package/src/rules/no-hardcoded-api-keys/index.js +5 -28
  8. package/src/rules/no-sensitive-in-prompt/index.js +0 -20
  9. package/src/rules/no-system-prompt-leak/index.js +0 -25
  10. package/src/rules/no-training-data-exposure/index.js +0 -16
  11. package/src/rules/no-unsafe-output-handling/index.js +0 -35
  12. package/src/rules/require-abort-signal/index.js +0 -14
  13. package/src/rules/require-audit-logging/index.js +0 -24
  14. package/src/rules/require-embedding-validation/index.js +0 -23
  15. package/src/rules/require-error-handling/index.js +0 -19
  16. package/src/rules/require-max-steps/index.js +0 -18
  17. package/src/rules/require-max-tokens/index.js +0 -14
  18. package/src/rules/require-output-filtering/index.js +0 -23
  19. package/src/rules/require-output-validation/index.js +0 -23
  20. package/src/rules/require-rag-content-validation/index.js +0 -28
  21. package/src/rules/require-request-timeout/index.js +0 -16
  22. package/src/rules/require-tool-confirmation/index.js +1 -25
  23. package/src/rules/require-tool-schema/index.js +0 -19
  24. package/src/rules/require-validated-prompt/index.js +0 -33
  25. package/src/types/index.js +0 -5
  26. package/src/utils/prompt-props.js +0 -23
  27. package/AGENTS.md +0 -131
  28. package/CHANGELOG.md +0 -255
  29. package/src/rules/no-dynamic-system-prompt/index.d.ts +0 -14
  30. package/src/rules/no-hardcoded-api-keys/index.d.ts +0 -14
  31. package/src/rules/no-sensitive-in-prompt/index.d.ts +0 -14
  32. package/src/rules/no-system-prompt-leak/index.d.ts +0 -14
  33. package/src/rules/no-training-data-exposure/index.d.ts +0 -14
  34. package/src/rules/no-unsafe-output-handling/index.d.ts +0 -15
  35. package/src/rules/require-abort-signal/index.d.ts +0 -14
  36. package/src/rules/require-audit-logging/index.d.ts +0 -14
  37. package/src/rules/require-embedding-validation/index.d.ts +0 -16
  38. package/src/rules/require-error-handling/index.d.ts +0 -14
  39. package/src/rules/require-max-steps/index.d.ts +0 -14
  40. package/src/rules/require-max-tokens/index.d.ts +0 -16
  41. package/src/rules/require-output-filtering/index.d.ts +0 -16
  42. package/src/rules/require-output-validation/index.d.ts +0 -16
  43. package/src/rules/require-rag-content-validation/index.d.ts +0 -16
  44. package/src/rules/require-request-timeout/index.d.ts +0 -14
  45. package/src/rules/require-tool-confirmation/index.d.ts +0 -14
  46. package/src/rules/require-tool-schema/index.d.ts +0 -15
  47. package/src/rules/require-validated-prompt/index.d.ts +0 -19
  48. package/src/utils/prompt-props.d.ts +0 -27
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-vercel-ai-security",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "ESLint plugin for Vercel AI SDK security — detects prompt injection, system-prompt leaks, hardcoded API keys, and unvalidated model output in generateText and streamText.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -24,7 +24,7 @@
24
24
  "homepage": "https://eslint.interlace.tools/docs/security/plugin-vercel-ai-security?utm_source=npm&utm_medium=referral&utm_campaign=eslint-plugin-vercel-ai-security",
25
25
  "repository": {
26
26
  "type": "git",
27
- "url": "https://github.com/ofri-peretz/eslint",
27
+ "url": "git+https://github.com/ofri-peretz/eslint.git",
28
28
  "directory": "packages/eslint-plugin-vercel-ai-security"
29
29
  },
30
30
  "bugs": {
@@ -35,11 +35,8 @@
35
35
  },
36
36
  "files": [
37
37
  "src/",
38
- "dist/",
39
38
  "README.md",
40
- "LICENSE",
41
- "CHANGELOG.md",
42
- "AGENTS.md"
39
+ "LICENSE"
43
40
  ],
44
41
  "keywords": [
45
42
  "eslint",
@@ -86,22 +83,10 @@
86
83
  },
87
84
  "dependencies": {
88
85
  "tslib": "^2.3.0",
89
- "@interlace/eslint-devkit": "^1.4.4"
90
- },
91
- "devDependencies": {
92
- "@ai-sdk/openai": "^4.0.16",
93
- "@typescript-eslint/parser": "^8.46.2",
94
- "@typescript-eslint/rule-tester": "^8.46.2",
95
- "ai": "^7.0.31"
96
- },
97
- "scripts": {
98
- "build": "tsx ../../scripts/build-package.ts",
99
- "test": "vitest run",
100
- "test:coverage": "vitest run --coverage",
101
- "typecheck": "tsc -p tsconfig.lib.json --noEmit"
86
+ "@interlace/eslint-devkit": "^1.6.1"
102
87
  },
103
88
  "funding": {
104
89
  "type": "github",
105
- "url": "https://github.com/ofri-peretz/eslint"
90
+ "url": "git+https://github.com/ofri-peretz/eslint.git"
106
91
  }
107
92
  }
package/src/index.d.ts CHANGED
@@ -1,74 +1,17 @@
1
- /**
2
- * Copyright (c) 2025 Ofri Peretz
3
- * Licensed under the MIT License. Use of this source code is governed by the
4
- * MIT license that can be found in the LICENSE file.
5
- */
6
- /**
7
- * eslint-plugin-vercel-ai-security
8
- *
9
- * Security-focused ESLint plugin for Vercel AI SDK.
10
- * SDK-aware rules with full type knowledge for generateText, streamText, tools, and streaming.
11
- *
12
- * Covers OWASP Top 10 for LLM Applications 2025 and OWASP Agentic Top 10 2026.
13
- *
14
- * @see https://sdk.vercel.ai/docs
15
- * @see https://owasp.org/www-project-top-10-for-large-language-model-applications/
16
- */
17
- import type { TSESLint } from '@interlace/eslint-devkit';
18
- export { requireValidatedPrompt } from './rules/require-validated-prompt';
19
- export { noSensitiveInPrompt } from './rules/no-sensitive-in-prompt';
20
- export { noTrainingDataExposure } from './rules/no-training-data-exposure';
21
- export { requireRequestTimeout } from './rules/require-request-timeout';
22
- export { noUnsafeOutputHandling } from './rules/no-unsafe-output-handling';
23
- export { requireToolConfirmation } from './rules/require-tool-confirmation';
24
- export { noSystemPromptLeak } from './rules/no-system-prompt-leak';
25
- export { requireEmbeddingValidation } from './rules/require-embedding-validation';
26
- export { requireOutputValidation } from './rules/require-output-validation';
27
- export { requireMaxTokens } from './rules/require-max-tokens';
28
- export { requireMaxSteps } from './rules/require-max-steps';
29
- export { requireAbortSignal } from './rules/require-abort-signal';
30
- export { noDynamicSystemPrompt } from './rules/no-dynamic-system-prompt';
31
- export { requireToolSchema } from './rules/require-tool-schema';
32
- export { noHardcodedApiKeys } from './rules/no-hardcoded-api-keys';
33
- export { requireOutputFiltering } from './rules/require-output-filtering';
34
- export { requireRagContentValidation } from './rules/require-rag-content-validation';
35
- export { requireErrorHandling } from './rules/require-error-handling';
36
- export { requireAuditLogging } from './rules/require-audit-logging';
37
- /**
38
- * Collection of all Vercel AI SDK security ESLint rules (19 total)
39
- *
40
- * OWASP Top 10 for LLM Applications 2025 (10/10):
41
- * - LLM01: Prompt Injection → require-validated-prompt
42
- * - LLM02: Sensitive Info Disclosure → no-sensitive-in-prompt
43
- * - LLM03: Training Data Poisoning → no-training-data-exposure
44
- * - LLM04: Model Denial of Service → require-request-timeout
45
- * - LLM05: Improper Output Handling → no-unsafe-output-handling
46
- * - LLM06: Excessive Agency → require-tool-confirmation
47
- * - LLM07: System Prompt Leakage → no-system-prompt-leak
48
- * - LLM08: Vector & Embedding Weaknesses → require-embedding-validation
49
- * - LLM09: Misinformation → require-output-validation
50
- * - LLM10: Unbounded Consumption → require-max-tokens, require-max-steps, require-abort-signal
51
- *
52
- * OWASP Agentic Top 10 2026 (9/10 - ASI06 N/A for TypeScript):
53
- * - ASI01: Agent Confusion → no-dynamic-system-prompt
54
- * - ASI02: Tool Misuse → require-tool-schema
55
- * - ASI03: Identity Abuse → no-hardcoded-api-keys
56
- * - ASI04: Data Exfiltration → require-output-filtering
57
- * - ASI05: Unexpected Code Execution → no-unsafe-output-handling
58
- * - ASI06: Memory Corruption → N/A (TypeScript is memory-safe)
59
- * - ASI07: Poisoned RAG → require-rag-content-validation
60
- * - ASI08: Cascading Failures → require-error-handling
61
- * - ASI09: Human-Agent Trust → require-tool-confirmation
62
- * - ASI10: Logging & Monitoring → require-audit-logging
63
- */
64
- export declare const rules: Record<string, TSESLint.RuleModule<string, readonly unknown[]>>;
65
- /**
66
- * ESLint plugin object
67
- */
68
- export declare const plugin: TSESLint.FlatConfig.Plugin;
69
- /**
70
- * Available configurations (3 options)
71
- */
72
- export declare const configs: Record<string, TSESLint.FlatConfig.Config>;
73
- export default plugin;
74
- export type * from './types/index';
1
+ // Minimal declaration written by scripts/build-package.ts.
2
+ //
3
+ // tsc's generated entry declaration inlined every inferred rule-option type
4
+ // (up to 166 kB per plugin) for an API no consumer calls directly. This types
5
+ // what a flat config actually touches. Per-rule option types remain available
6
+ // from the "./types" subpath export where a plugin provides one.
7
+ import type { Linter, Rule } from 'eslint';
8
+
9
+ export declare const rules: Record<string, Rule.RuleModule>;
10
+ export declare const configs: Record<string, Linter.Config>;
11
+ export declare const plugin: {
12
+ meta: { name: string; version: string };
13
+ rules: Record<string, Rule.RuleModule>;
14
+ };
15
+
16
+ declare const _default: typeof plugin;
17
+ export default _default;
package/src/index.js CHANGED
@@ -1,48 +1,25 @@
1
1
  "use strict";
2
- /**
3
- * Copyright (c) 2025 Ofri Peretz
4
- * Licensed under the MIT License. Use of this source code is governed by the
5
- * MIT license that can be found in the LICENSE file.
6
- */
7
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.configs = exports.plugin = exports.rules = exports.requireAuditLogging = exports.requireErrorHandling = exports.requireRagContentValidation = exports.requireOutputFiltering = exports.noHardcodedApiKeys = exports.requireToolSchema = exports.noDynamicSystemPrompt = exports.requireAbortSignal = exports.requireMaxSteps = exports.requireMaxTokens = exports.requireOutputValidation = exports.requireEmbeddingValidation = exports.noSystemPromptLeak = exports.requireToolConfirmation = exports.noUnsafeOutputHandling = exports.requireRequestTimeout = exports.noTrainingDataExposure = exports.noSensitiveInPrompt = exports.requireValidatedPrompt = void 0;
9
- // Import rules - LLM01: Prompt Injection
10
4
  const require_validated_prompt_1 = require("./rules/require-validated-prompt");
11
- // LLM02: Sensitive Information Disclosure
12
5
  const no_sensitive_in_prompt_1 = require("./rules/no-sensitive-in-prompt");
13
- // LLM03: Training Data Poisoning
14
6
  const no_training_data_exposure_1 = require("./rules/no-training-data-exposure");
15
- // LLM04: Model Denial of Service
16
7
  const require_request_timeout_1 = require("./rules/require-request-timeout");
17
- // LLM05/ASI05: Improper Output Handling / Unexpected Code Execution
18
8
  const no_unsafe_output_handling_1 = require("./rules/no-unsafe-output-handling");
19
- // LLM06/ASI09: Excessive Agency / Human-Agent Trust
20
9
  const require_tool_confirmation_1 = require("./rules/require-tool-confirmation");
21
- // LLM07: System Prompt Leakage
22
10
  const no_system_prompt_leak_1 = require("./rules/no-system-prompt-leak");
23
- // LLM08: Vector & Embedding Weaknesses
24
11
  const require_embedding_validation_1 = require("./rules/require-embedding-validation");
25
- // LLM09: Misinformation
26
12
  const require_output_validation_1 = require("./rules/require-output-validation");
27
- // LLM10: Unbounded Consumption
28
13
  const require_max_tokens_1 = require("./rules/require-max-tokens");
29
14
  const require_max_steps_1 = require("./rules/require-max-steps");
30
15
  const require_abort_signal_1 = require("./rules/require-abort-signal");
31
- // ASI01: Agent Confusion
32
16
  const no_dynamic_system_prompt_1 = require("./rules/no-dynamic-system-prompt");
33
- // ASI02: Tool Misuse & Exploitation
34
17
  const require_tool_schema_1 = require("./rules/require-tool-schema");
35
- // ASI03: Identity & Privilege Abuse
36
18
  const no_hardcoded_api_keys_1 = require("./rules/no-hardcoded-api-keys");
37
- // ASI04: Data Exfiltration
38
19
  const require_output_filtering_1 = require("./rules/require-output-filtering");
39
- // ASI07: Poisoned RAG Pipeline
40
20
  const require_rag_content_validation_1 = require("./rules/require-rag-content-validation");
41
- // ASI08: Cascading Failures
42
21
  const require_error_handling_1 = require("./rules/require-error-handling");
43
- // ASI10: Logging & Monitoring
44
22
  const require_audit_logging_1 = require("./rules/require-audit-logging");
45
- // Re-export all rules
46
23
  var require_validated_prompt_2 = require("./rules/require-validated-prompt");
47
24
  Object.defineProperty(exports, "requireValidatedPrompt", { enumerable: true, get: function () { return require_validated_prompt_2.requireValidatedPrompt; } });
48
25
  var no_sensitive_in_prompt_2 = require("./rules/no-sensitive-in-prompt");
@@ -81,85 +58,34 @@ var require_error_handling_2 = require("./rules/require-error-handling");
81
58
  Object.defineProperty(exports, "requireErrorHandling", { enumerable: true, get: function () { return require_error_handling_2.requireErrorHandling; } });
82
59
  var require_audit_logging_2 = require("./rules/require-audit-logging");
83
60
  Object.defineProperty(exports, "requireAuditLogging", { enumerable: true, get: function () { return require_audit_logging_2.requireAuditLogging; } });
84
- /**
85
- * Collection of all Vercel AI SDK security ESLint rules (19 total)
86
- *
87
- * OWASP Top 10 for LLM Applications 2025 (10/10):
88
- * - LLM01: Prompt Injection → require-validated-prompt
89
- * - LLM02: Sensitive Info Disclosure → no-sensitive-in-prompt
90
- * - LLM03: Training Data Poisoning → no-training-data-exposure
91
- * - LLM04: Model Denial of Service → require-request-timeout
92
- * - LLM05: Improper Output Handling → no-unsafe-output-handling
93
- * - LLM06: Excessive Agency → require-tool-confirmation
94
- * - LLM07: System Prompt Leakage → no-system-prompt-leak
95
- * - LLM08: Vector & Embedding Weaknesses → require-embedding-validation
96
- * - LLM09: Misinformation → require-output-validation
97
- * - LLM10: Unbounded Consumption → require-max-tokens, require-max-steps, require-abort-signal
98
- *
99
- * OWASP Agentic Top 10 2026 (9/10 - ASI06 N/A for TypeScript):
100
- * - ASI01: Agent Confusion → no-dynamic-system-prompt
101
- * - ASI02: Tool Misuse → require-tool-schema
102
- * - ASI03: Identity Abuse → no-hardcoded-api-keys
103
- * - ASI04: Data Exfiltration → require-output-filtering
104
- * - ASI05: Unexpected Code Execution → no-unsafe-output-handling
105
- * - ASI06: Memory Corruption → N/A (TypeScript is memory-safe)
106
- * - ASI07: Poisoned RAG → require-rag-content-validation
107
- * - ASI08: Cascading Failures → require-error-handling
108
- * - ASI09: Human-Agent Trust → require-tool-confirmation
109
- * - ASI10: Logging & Monitoring → require-audit-logging
110
- */
111
61
  exports.rules = {
112
- // OWASP LLM01: Prompt Injection
113
62
  'require-validated-prompt': require_validated_prompt_1.requireValidatedPrompt,
114
- // OWASP LLM02: Sensitive Information Disclosure
115
63
  'no-sensitive-in-prompt': no_sensitive_in_prompt_1.noSensitiveInPrompt,
116
- // OWASP LLM03: Training Data Poisoning
117
64
  'no-training-data-exposure': no_training_data_exposure_1.noTrainingDataExposure,
118
- // OWASP LLM04: Model Denial of Service
119
65
  'require-request-timeout': require_request_timeout_1.requireRequestTimeout,
120
- // OWASP LLM05: Improper Output Handling / ASI05: Code Execution
121
66
  'no-unsafe-output-handling': no_unsafe_output_handling_1.noUnsafeOutputHandling,
122
- // OWASP LLM06: Excessive Agency / ASI09: Human-Agent Trust
123
67
  'require-tool-confirmation': require_tool_confirmation_1.requireToolConfirmation,
124
- // OWASP LLM07: System Prompt Leakage
125
68
  'no-system-prompt-leak': no_system_prompt_leak_1.noSystemPromptLeak,
126
- // OWASP LLM08: Vector & Embedding Weaknesses
127
69
  'require-embedding-validation': require_embedding_validation_1.requireEmbeddingValidation,
128
- // OWASP LLM09: Misinformation
129
70
  'require-output-validation': require_output_validation_1.requireOutputValidation,
130
- // OWASP LLM10: Unbounded Consumption
131
71
  'require-max-tokens': require_max_tokens_1.requireMaxTokens,
132
72
  'require-max-steps': require_max_steps_1.requireMaxSteps,
133
73
  'require-abort-signal': require_abort_signal_1.requireAbortSignal,
134
- // OWASP ASI01: Agent Confusion
135
74
  'no-dynamic-system-prompt': no_dynamic_system_prompt_1.noDynamicSystemPrompt,
136
- // OWASP ASI02: Tool Misuse & Exploitation
137
75
  'require-tool-schema': require_tool_schema_1.requireToolSchema,
138
- // OWASP ASI03: Identity & Privilege Abuse
139
76
  'no-hardcoded-api-keys': no_hardcoded_api_keys_1.noHardcodedApiKeys,
140
- // OWASP ASI04: Data Exfiltration
141
77
  'require-output-filtering': require_output_filtering_1.requireOutputFiltering,
142
- // OWASP ASI07: Poisoned RAG Pipeline
143
78
  'require-rag-content-validation': require_rag_content_validation_1.requireRagContentValidation,
144
- // OWASP ASI08: Cascading Failures
145
79
  'require-error-handling': require_error_handling_1.requireErrorHandling,
146
- // OWASP ASI10: Logging & Monitoring
147
80
  'require-audit-logging': require_audit_logging_1.requireAuditLogging,
148
81
  };
149
- /**
150
- * ESLint plugin object
151
- */
152
82
  exports.plugin = {
153
83
  meta: {
154
84
  name: 'eslint-plugin-vercel-ai-security',
155
- version: '1.4.0',
85
+ version: '1.4.1',
156
86
  },
157
87
  rules: exports.rules,
158
88
  };
159
- /**
160
- * Minimal configuration - for gradual adoption
161
- * Only the 2 most critical rules
162
- */
163
89
  const minimalConfig = {
164
90
  plugins: {
165
91
  'vercel-ai-security': exports.plugin,
@@ -169,16 +95,11 @@ const minimalConfig = {
169
95
  'vercel-ai-security/no-hardcoded-api-keys': 'error',
170
96
  },
171
97
  };
172
- /**
173
- * Recommended configuration - balanced security
174
- * Critical rules as errors, high-priority as warnings
175
- */
176
98
  const recommendedConfig = {
177
99
  plugins: {
178
100
  'vercel-ai-security': exports.plugin,
179
101
  },
180
102
  rules: {
181
- // Critical - always enabled as errors (LLM01-02, LLM05-07)
182
103
  'vercel-ai-security/require-validated-prompt': 'error',
183
104
  'vercel-ai-security/no-hardcoded-api-keys': 'error',
184
105
  'vercel-ai-security/no-unsafe-output-handling': 'error',
@@ -186,7 +107,6 @@ const recommendedConfig = {
186
107
  'vercel-ai-security/no-system-prompt-leak': 'error',
187
108
  'vercel-ai-security/no-dynamic-system-prompt': 'error',
188
109
  'vercel-ai-security/require-tool-confirmation': 'error',
189
- // High - enabled as warnings
190
110
  'vercel-ai-security/require-tool-schema': 'error',
191
111
  'vercel-ai-security/require-max-tokens': 'error',
192
112
  'vercel-ai-security/require-max-steps': 'error',
@@ -194,7 +114,6 @@ const recommendedConfig = {
194
114
  'vercel-ai-security/require-rag-content-validation': 'warn',
195
115
  'vercel-ai-security/no-training-data-exposure': 'warn',
196
116
  'vercel-ai-security/require-request-timeout': 'warn',
197
- // Medium - disabled by default
198
117
  'vercel-ai-security/require-error-handling': 'off',
199
118
  'vercel-ai-security/require-abort-signal': 'error',
200
119
  'vercel-ai-security/require-audit-logging': 'off',
@@ -202,16 +121,11 @@ const recommendedConfig = {
202
121
  'vercel-ai-security/require-output-validation': 'off',
203
122
  },
204
123
  };
205
- /**
206
- * Strict configuration - maximum security
207
- * All rules enabled for production deployments
208
- */
209
124
  const strictConfig = {
210
125
  plugins: {
211
126
  'vercel-ai-security': exports.plugin,
212
127
  },
213
128
  rules: {
214
- // All critical and high as errors
215
129
  'vercel-ai-security/require-validated-prompt': 'error',
216
130
  'vercel-ai-security/no-hardcoded-api-keys': 'error',
217
131
  'vercel-ai-security/no-unsafe-output-handling': 'error',
@@ -233,15 +147,7 @@ const strictConfig = {
233
147
  'vercel-ai-security/require-audit-logging': 'warn',
234
148
  },
235
149
  };
236
- /**
237
- * Available configurations (3 options)
238
- */
239
150
  exports.configs = {
240
- /**
241
- * Flagship preset — the rule from this plugin in the ecosystem-wide
242
- * flagship list (`.agent/flagship-rules.md`). Anchors the OWASP LLM02
243
- * niche — green-field, no competitor.
244
- */
245
151
  flagship: {
246
152
  plugins: {
247
153
  'vercel-ai-security': exports.plugin,
@@ -250,12 +156,8 @@ exports.configs = {
250
156
  'vercel-ai-security/no-unsafe-output-handling': 'error',
251
157
  },
252
158
  },
253
- /** Minimal: 2 critical rules for gradual adoption */
254
159
  minimal: minimalConfig,
255
- /** Recommended: Balanced security (7 errors, 7 warnings) */
256
160
  recommended: recommendedConfig,
257
- /** Strict: Maximum security (17 errors, 2 warnings) */
258
161
  strict: strictConfig,
259
162
  };
260
- // Default export
261
163
  exports.default = exports.plugin;
package/src/oxlint.d.ts CHANGED
@@ -1,20 +1,17 @@
1
- /**
2
- * Copyright (c) 2025 Ofri Peretz
3
- * Licensed under the MIT License. Use of this source code is governed by the
4
- * MIT license that can be found in the LICENSE file.
5
- */
6
- /**
7
- * oxlint sub-export.
8
- *
9
- * Consumers wire oxlint to this entry via:
10
- * { "jsPlugins": ["eslint-plugin-vercel-ai-security/oxlint"] }
11
- *
12
- * oxlint's JS plugin loader does `require('eslint-plugin-vercel-ai-security/oxlint')` and reads
13
- * `.rules` off the result. The compiled output of `export = plugin` is
14
- * `module.exports = plugin`, which gives oxlint the plugin object directly
15
- * (`{ meta, rules }`) — no wrapper, no `.default` indirection.
16
- *
17
- * Generated by scripts/generate-oxlint-shims.mjs. Do not edit by hand.
18
- */
19
- import { plugin } from './index';
20
- export = plugin;
1
+ // Minimal declaration written by scripts/build-package.ts.
2
+ //
3
+ // tsc's generated entry declaration inlined every inferred rule-option type
4
+ // (up to 166 kB per plugin) for an API no consumer calls directly. This types
5
+ // what a flat config actually touches. Per-rule option types remain available
6
+ // from the "./types" subpath export where a plugin provides one.
7
+ import type { Linter, Rule } from 'eslint';
8
+
9
+ export declare const rules: Record<string, Rule.RuleModule>;
10
+ export declare const configs: Record<string, Linter.Config>;
11
+ export declare const plugin: {
12
+ meta: { name: string; version: string };
13
+ rules: Record<string, Rule.RuleModule>;
14
+ };
15
+
16
+ declare const _default: typeof plugin;
17
+ export default _default;
package/src/oxlint.js CHANGED
@@ -1,21 +1,3 @@
1
1
  "use strict";
2
- /**
3
- * Copyright (c) 2025 Ofri Peretz
4
- * Licensed under the MIT License. Use of this source code is governed by the
5
- * MIT license that can be found in the LICENSE file.
6
- */
7
- /**
8
- * oxlint sub-export.
9
- *
10
- * Consumers wire oxlint to this entry via:
11
- * { "jsPlugins": ["eslint-plugin-vercel-ai-security/oxlint"] }
12
- *
13
- * oxlint's JS plugin loader does `require('eslint-plugin-vercel-ai-security/oxlint')` and reads
14
- * `.rules` off the result. The compiled output of `export = plugin` is
15
- * `module.exports = plugin`, which gives oxlint the plugin object directly
16
- * (`{ meta, rules }`) — no wrapper, no `.default` indirection.
17
- *
18
- * Generated by scripts/generate-oxlint-shims.mjs. Do not edit by hand.
19
- */
20
2
  const index_1 = require("./index");
21
3
  module.exports = index_1.plugin;
@@ -1,16 +1,6 @@
1
1
  "use strict";
2
- /**
3
- * Copyright (c) 2025 Ofri Peretz
4
- * Licensed under the MIT License. Use of this source code is governed by the
5
- * MIT license that can be found in the LICENSE file.
6
- */
7
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noDynamicSystemPrompt = void 0;
9
- /**
10
- * @fileoverview Prevent dynamic content in system prompts
11
- * @description Detects when system prompts contain dynamic/user-controlled content
12
- * @see OWASP ASI01: Agent Confusion
13
- */
14
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
5
  const prompt_props_1 = require("../../utils/prompt-props");
16
6
  exports.noDynamicSystemPrompt = (0, eslint_devkit_1.createRule)({
@@ -59,28 +49,20 @@ exports.noDynamicSystemPrompt = (0, eslint_devkit_1.createRule)({
59
49
  const [options = {}] = context.options;
60
50
  const allowStaticTemplates = options.allowStaticTemplates ?? true;
61
51
  const sourceCode = context.sourceCode;
62
- // Vercel AI SDK functions
63
52
  const aiSDKFunctions = ['generateText', 'streamText', 'generateObject', 'streamObject'];
64
- /**
65
- * Check if a node represents dynamic content
66
- */
67
53
  function isDynamicContent(node) {
68
- // Template literal with expressions
69
54
  if (node.type === 'TemplateLiteral') {
70
55
  if (node.expressions.length > 0) {
71
56
  return true;
72
57
  }
73
58
  return !allowStaticTemplates;
74
59
  }
75
- // Binary expression (concatenation)
76
60
  if (node.type === 'BinaryExpression' && node.operator === '+') {
77
61
  return true;
78
62
  }
79
- // Call expression (function result)
80
63
  if (node.type === 'CallExpression') {
81
64
  return true;
82
65
  }
83
- // Await expression
84
66
  if (node.type === 'AwaitExpression') {
85
67
  return true;
86
68
  }
@@ -89,22 +71,18 @@ exports.noDynamicSystemPrompt = (0, eslint_devkit_1.createRule)({
89
71
  return {
90
72
  CallExpression(node) {
91
73
  const callee = sourceCode.getText(node.callee);
92
- // Check if this is an AI SDK function
93
74
  const isAIFunction = aiSDKFunctions.some(fn => callee.includes(fn));
94
75
  if (!isAIFunction)
95
76
  return;
96
- // Check first argument (options object)
97
77
  const optionsArg = node.arguments[0];
98
78
  if (!optionsArg || optionsArg.type !== 'ObjectExpression')
99
79
  return;
100
- // Find the system-prompt property (`instructions` in AI SDK v7+, `system` before it)
101
80
  for (const prop of optionsArg.properties) {
102
81
  if (prop.type !== eslint_devkit_1.AST_NODE_TYPES.Property)
103
82
  continue;
104
83
  const keyName = (0, prompt_props_1.getStaticPropName)(prop.key);
105
84
  if (!(0, prompt_props_1.isSystemPromptProp)(keyName))
106
85
  continue;
107
- // Check if system prompt is dynamic
108
86
  if (isDynamicContent(prop.value)) {
109
87
  context.report({
110
88
  node: prop.value,
@@ -1,16 +1,6 @@
1
1
  "use strict";
2
- /**
3
- * Copyright (c) 2025 Ofri Peretz
4
- * Licensed under the MIT License. Use of this source code is governed by the
5
- * MIT license that can be found in the LICENSE file.
6
- */
7
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noHardcodedApiKeys = void 0;
9
- /**
10
- * @fileoverview Prevent hardcoded API keys in AI SDK calls
11
- * @description Detects hardcoded API keys/secrets in model configuration
12
- * @see OWASP ASI03: Identity & Privilege Abuse
13
- */
14
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
5
  exports.noHardcodedApiKeys = (0, eslint_devkit_1.createRule)({
16
6
  name: 'no-hardcoded-api-keys',
@@ -61,23 +51,17 @@ exports.noHardcodedApiKeys = (0, eslint_devkit_1.createRule)({
61
51
  'apiKey', 'api_key', 'token', 'secret', 'credentials',
62
52
  ];
63
53
  const sourceCode = context.sourceCode;
64
- // Known model provider functions
65
54
  const providerFunctions = [
66
55
  'openai', 'anthropic', 'google', 'cohere', 'mistral',
67
56
  'createOpenAI', 'createAnthropic', 'createGoogle', 'createMistral',
68
57
  ];
69
- /**
70
- * Check if a string looks like an API key
71
- */
72
- // oxlint-disable-next-line consistent-function-scoping
73
58
  function looksLikeApiKey(value) {
74
- // Common API key patterns
75
59
  const patterns = [
76
- /^sk-[a-zA-Z0-9]{20,}$/, // OpenAI
77
- /^sk-ant-[a-zA-Z0-9-]+$/, // Anthropic
78
- /^[a-zA-Z0-9]{32,}$/, // Generic long alphanumeric
79
- /^[A-Z0-9]{20,}$/, // AWS-style keys
80
- /^AIza[a-zA-Z0-9-_]{35}$/, // Google AI
60
+ /^sk-[a-zA-Z0-9]{20,}$/,
61
+ /^sk-ant-[a-zA-Z0-9-]+$/,
62
+ /^[a-zA-Z0-9]{32,}$/,
63
+ /^[A-Z0-9]{20,}$/,
64
+ /^AIza[a-zA-Z0-9-_]{35}$/,
81
65
  ];
82
66
  return patterns.some(p => p.test(value));
83
67
  }
@@ -90,18 +74,14 @@ exports.noHardcodedApiKeys = (0, eslint_devkit_1.createRule)({
90
74
  : null;
91
75
  if (!keyName)
92
76
  return;
93
- // Check if this is an API key property
94
77
  const isApiKeyProp = apiKeyPatterns.some((pattern) => keyName.toLowerCase().includes(pattern.toLowerCase()));
95
78
  if (!isApiKeyProp)
96
79
  return;
97
- // Check if value is a hardcoded string
98
80
  if (node.value.type === 'Literal' && typeof node.value.value === 'string') {
99
81
  const value = node.value.value;
100
- // Skip placeholder values
101
82
  if (value === '' || value === 'YOUR_API_KEY' || value.startsWith('$')) {
102
83
  return;
103
84
  }
104
- // Report if it looks like a real API key
105
85
  if (looksLikeApiKey(value) || value.length > 20) {
106
86
  context.report({
107
87
  node: node.value,
@@ -111,14 +91,11 @@ exports.noHardcodedApiKeys = (0, eslint_devkit_1.createRule)({
111
91
  }
112
92
  }
113
93
  },
114
- // Also check model provider function calls
115
94
  CallExpression(node) {
116
95
  const callee = sourceCode.getText(node.callee);
117
- // Check if this is a model provider function
118
96
  const isProvider = providerFunctions.some(fn => callee.includes(fn));
119
97
  if (!isProvider)
120
98
  return;
121
- // Check if second argument is options with apiKey
122
99
  const optionsArg = node.arguments[1];
123
100
  if (optionsArg && optionsArg.type === 'ObjectExpression') {
124
101
  for (const prop of optionsArg.properties) {
@@ -1,16 +1,6 @@
1
1
  "use strict";
2
- /**
3
- * Copyright (c) 2025 Ofri Peretz
4
- * Licensed under the MIT License. Use of this source code is governed by the
5
- * MIT license that can be found in the LICENSE file.
6
- */
7
2
  Object.defineProperty(exports, "__esModule", { value: true });
8
3
  exports.noSensitiveInPrompt = void 0;
9
- /**
10
- * @fileoverview Prevent sensitive data from being passed to LLM prompts
11
- * @description Detects secrets, credentials, PII in prompts
12
- * @see OWASP LLM02: Sensitive Information Disclosure
13
- */
14
4
  const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
5
  const prompt_props_1 = require("../../utils/prompt-props");
16
6
  exports.noSensitiveInPrompt = (0, eslint_devkit_1.createRule)({
@@ -69,18 +59,11 @@ exports.noSensitiveInPrompt = (0, eslint_devkit_1.createRule)({
69
59
  'ssn', 'creditCard', 'privateKey', 'accessToken',
70
60
  ];
71
61
  const sourceCode = context.sourceCode;
72
- // Vercel AI SDK functions
73
62
  const aiSDKFunctions = ['generateText', 'streamText', 'generateObject', 'streamObject'];
74
- /**
75
- * Check if an identifier name matches sensitive patterns
76
- */
77
63
  function isSensitiveIdentifier(name) {
78
64
  const lowerName = name.toLowerCase();
79
65
  return sensitivePatterns.some((pattern) => lowerName.includes(pattern.toLowerCase()));
80
66
  }
81
- /**
82
- * Check if a node contains sensitive data
83
- */
84
67
  function findSensitiveData(node) {
85
68
  if (node.type === 'Identifier' && isSensitiveIdentifier(node.name)) {
86
69
  return node.name;
@@ -110,15 +93,12 @@ exports.noSensitiveInPrompt = (0, eslint_devkit_1.createRule)({
110
93
  return {
111
94
  CallExpression(node) {
112
95
  const callee = sourceCode.getText(node.callee);
113
- // Check if this is an AI SDK function
114
96
  const isAIFunction = aiSDKFunctions.some(fn => callee.includes(fn));
115
97
  if (!isAIFunction)
116
98
  return;
117
- // Check first argument (options object)
118
99
  const optionsArg = node.arguments[0];
119
100
  if (!optionsArg || optionsArg.type !== 'ObjectExpression')
120
101
  return;
121
- // Check prompt, the system-prompt props, and messages
122
102
  const propsToCheck = new Set(['prompt', 'messages', ...prompt_props_1.SYSTEM_PROMPT_PROPS]);
123
103
  for (const prop of optionsArg.properties) {
124
104
  if (prop.type !== eslint_devkit_1.AST_NODE_TYPES.Property)