eslint-plugin-vercel-ai-security 2.1.1 → 2.1.2
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-vercel-ai-security",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
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",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@interlace/eslint-devkit": "^1.
|
|
86
|
+
"@interlace/eslint-devkit": "^1.19.0"
|
|
87
87
|
},
|
|
88
88
|
"funding": {
|
|
89
89
|
"type": "github",
|
package/src/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});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;const eslint_devkit_1=require("@interlace/eslint-devkit");var require_validated_prompt_2=require("./rules/require-validated-prompt");Object.defineProperty(exports,"requireValidatedPrompt",{enumerable:true,get:function(){return require_validated_prompt_2.requireValidatedPrompt}});var no_sensitive_in_prompt_2=require("./rules/no-sensitive-in-prompt");Object.defineProperty(exports,"noSensitiveInPrompt",{enumerable:true,get:function(){return no_sensitive_in_prompt_2.noSensitiveInPrompt}});var no_training_data_exposure_2=require("./rules/no-training-data-exposure");Object.defineProperty(exports,"noTrainingDataExposure",{enumerable:true,get:function(){return no_training_data_exposure_2.noTrainingDataExposure}});var require_request_timeout_2=require("./rules/require-request-timeout");Object.defineProperty(exports,"requireRequestTimeout",{enumerable:true,get:function(){return require_request_timeout_2.requireRequestTimeout}});var no_unsafe_output_handling_2=require("./rules/no-unsafe-output-handling");Object.defineProperty(exports,"noUnsafeOutputHandling",{enumerable:true,get:function(){return no_unsafe_output_handling_2.noUnsafeOutputHandling}});var require_tool_confirmation_2=require("./rules/require-tool-confirmation");Object.defineProperty(exports,"requireToolConfirmation",{enumerable:true,get:function(){return require_tool_confirmation_2.requireToolConfirmation}});var no_system_prompt_leak_2=require("./rules/no-system-prompt-leak");Object.defineProperty(exports,"noSystemPromptLeak",{enumerable:true,get:function(){return no_system_prompt_leak_2.noSystemPromptLeak}});var require_embedding_validation_2=require("./rules/require-embedding-validation");Object.defineProperty(exports,"requireEmbeddingValidation",{enumerable:true,get:function(){return require_embedding_validation_2.requireEmbeddingValidation}});var require_output_validation_2=require("./rules/require-output-validation");Object.defineProperty(exports,"requireOutputValidation",{enumerable:true,get:function(){return require_output_validation_2.requireOutputValidation}});var require_max_tokens_2=require("./rules/require-max-tokens");Object.defineProperty(exports,"requireMaxTokens",{enumerable:true,get:function(){return require_max_tokens_2.requireMaxTokens}});var require_max_steps_2=require("./rules/require-max-steps");Object.defineProperty(exports,"requireMaxSteps",{enumerable:true,get:function(){return require_max_steps_2.requireMaxSteps}});var require_abort_signal_2=require("./rules/require-abort-signal");Object.defineProperty(exports,"requireAbortSignal",{enumerable:true,get:function(){return require_abort_signal_2.requireAbortSignal}});var no_dynamic_system_prompt_2=require("./rules/no-dynamic-system-prompt");Object.defineProperty(exports,"noDynamicSystemPrompt",{enumerable:true,get:function(){return no_dynamic_system_prompt_2.noDynamicSystemPrompt}});var require_tool_schema_2=require("./rules/require-tool-schema");Object.defineProperty(exports,"requireToolSchema",{enumerable:true,get:function(){return require_tool_schema_2.requireToolSchema}});var no_hardcoded_api_keys_2=require("./rules/no-hardcoded-api-keys");Object.defineProperty(exports,"noHardcodedApiKeys",{enumerable:true,get:function(){return no_hardcoded_api_keys_2.noHardcodedApiKeys}});var require_output_filtering_2=require("./rules/require-output-filtering");Object.defineProperty(exports,"requireOutputFiltering",{enumerable:true,get:function(){return require_output_filtering_2.requireOutputFiltering}});var require_rag_content_validation_2=require("./rules/require-rag-content-validation");Object.defineProperty(exports,"requireRagContentValidation",{enumerable:true,get:function(){return require_rag_content_validation_2.requireRagContentValidation}});var require_error_handling_2=require("./rules/require-error-handling");Object.defineProperty(exports,"requireErrorHandling",{enumerable:true,get:function(){return require_error_handling_2.requireErrorHandling}});var require_audit_logging_2=require("./rules/require-audit-logging");Object.defineProperty(exports,"requireAuditLogging",{enumerable:true,get:function(){return require_audit_logging_2.requireAuditLogging}});exports.rules={get"require-validated-prompt"(){return require("./rules/require-validated-prompt").requireValidatedPrompt},get"no-sensitive-in-prompt"(){return require("./rules/no-sensitive-in-prompt").noSensitiveInPrompt},get"no-training-data-exposure"(){return require("./rules/no-training-data-exposure").noTrainingDataExposure},get"require-request-timeout"(){return require("./rules/require-request-timeout").requireRequestTimeout},get"no-unsafe-output-handling"(){return require("./rules/no-unsafe-output-handling").noUnsafeOutputHandling},get"require-tool-confirmation"(){return require("./rules/require-tool-confirmation").requireToolConfirmation},get"no-system-prompt-leak"(){return require("./rules/no-system-prompt-leak").noSystemPromptLeak},get"require-embedding-validation"(){return require("./rules/require-embedding-validation").requireEmbeddingValidation},get"require-output-validation"(){return require("./rules/require-output-validation").requireOutputValidation},get"require-max-tokens"(){return require("./rules/require-max-tokens").requireMaxTokens},get"require-max-steps"(){return require("./rules/require-max-steps").requireMaxSteps},get"require-abort-signal"(){return require("./rules/require-abort-signal").requireAbortSignal},get"no-dynamic-system-prompt"(){return require("./rules/no-dynamic-system-prompt").noDynamicSystemPrompt},get"require-tool-schema"(){return require("./rules/require-tool-schema").requireToolSchema},get"no-hardcoded-api-keys"(){return require("./rules/no-hardcoded-api-keys").noHardcodedApiKeys},get"require-output-filtering"(){return require("./rules/require-output-filtering").requireOutputFiltering},get"require-rag-content-validation"(){return require("./rules/require-rag-content-validation").requireRagContentValidation},get"require-error-handling"(){return require("./rules/require-error-handling").requireErrorHandling},get"require-audit-logging"(){return require("./rules/require-audit-logging").requireAuditLogging}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-vercel-ai-security",exports.rules);exports.plugin={meta:{name:"eslint-plugin-vercel-ai-security",version:"2.1.
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});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;const eslint_devkit_1=require("@interlace/eslint-devkit");var require_validated_prompt_2=require("./rules/require-validated-prompt");Object.defineProperty(exports,"requireValidatedPrompt",{enumerable:true,get:function(){return require_validated_prompt_2.requireValidatedPrompt}});var no_sensitive_in_prompt_2=require("./rules/no-sensitive-in-prompt");Object.defineProperty(exports,"noSensitiveInPrompt",{enumerable:true,get:function(){return no_sensitive_in_prompt_2.noSensitiveInPrompt}});var no_training_data_exposure_2=require("./rules/no-training-data-exposure");Object.defineProperty(exports,"noTrainingDataExposure",{enumerable:true,get:function(){return no_training_data_exposure_2.noTrainingDataExposure}});var require_request_timeout_2=require("./rules/require-request-timeout");Object.defineProperty(exports,"requireRequestTimeout",{enumerable:true,get:function(){return require_request_timeout_2.requireRequestTimeout}});var no_unsafe_output_handling_2=require("./rules/no-unsafe-output-handling");Object.defineProperty(exports,"noUnsafeOutputHandling",{enumerable:true,get:function(){return no_unsafe_output_handling_2.noUnsafeOutputHandling}});var require_tool_confirmation_2=require("./rules/require-tool-confirmation");Object.defineProperty(exports,"requireToolConfirmation",{enumerable:true,get:function(){return require_tool_confirmation_2.requireToolConfirmation}});var no_system_prompt_leak_2=require("./rules/no-system-prompt-leak");Object.defineProperty(exports,"noSystemPromptLeak",{enumerable:true,get:function(){return no_system_prompt_leak_2.noSystemPromptLeak}});var require_embedding_validation_2=require("./rules/require-embedding-validation");Object.defineProperty(exports,"requireEmbeddingValidation",{enumerable:true,get:function(){return require_embedding_validation_2.requireEmbeddingValidation}});var require_output_validation_2=require("./rules/require-output-validation");Object.defineProperty(exports,"requireOutputValidation",{enumerable:true,get:function(){return require_output_validation_2.requireOutputValidation}});var require_max_tokens_2=require("./rules/require-max-tokens");Object.defineProperty(exports,"requireMaxTokens",{enumerable:true,get:function(){return require_max_tokens_2.requireMaxTokens}});var require_max_steps_2=require("./rules/require-max-steps");Object.defineProperty(exports,"requireMaxSteps",{enumerable:true,get:function(){return require_max_steps_2.requireMaxSteps}});var require_abort_signal_2=require("./rules/require-abort-signal");Object.defineProperty(exports,"requireAbortSignal",{enumerable:true,get:function(){return require_abort_signal_2.requireAbortSignal}});var no_dynamic_system_prompt_2=require("./rules/no-dynamic-system-prompt");Object.defineProperty(exports,"noDynamicSystemPrompt",{enumerable:true,get:function(){return no_dynamic_system_prompt_2.noDynamicSystemPrompt}});var require_tool_schema_2=require("./rules/require-tool-schema");Object.defineProperty(exports,"requireToolSchema",{enumerable:true,get:function(){return require_tool_schema_2.requireToolSchema}});var no_hardcoded_api_keys_2=require("./rules/no-hardcoded-api-keys");Object.defineProperty(exports,"noHardcodedApiKeys",{enumerable:true,get:function(){return no_hardcoded_api_keys_2.noHardcodedApiKeys}});var require_output_filtering_2=require("./rules/require-output-filtering");Object.defineProperty(exports,"requireOutputFiltering",{enumerable:true,get:function(){return require_output_filtering_2.requireOutputFiltering}});var require_rag_content_validation_2=require("./rules/require-rag-content-validation");Object.defineProperty(exports,"requireRagContentValidation",{enumerable:true,get:function(){return require_rag_content_validation_2.requireRagContentValidation}});var require_error_handling_2=require("./rules/require-error-handling");Object.defineProperty(exports,"requireErrorHandling",{enumerable:true,get:function(){return require_error_handling_2.requireErrorHandling}});var require_audit_logging_2=require("./rules/require-audit-logging");Object.defineProperty(exports,"requireAuditLogging",{enumerable:true,get:function(){return require_audit_logging_2.requireAuditLogging}});exports.rules={get"require-validated-prompt"(){return require("./rules/require-validated-prompt").requireValidatedPrompt},get"no-sensitive-in-prompt"(){return require("./rules/no-sensitive-in-prompt").noSensitiveInPrompt},get"no-training-data-exposure"(){return require("./rules/no-training-data-exposure").noTrainingDataExposure},get"require-request-timeout"(){return require("./rules/require-request-timeout").requireRequestTimeout},get"no-unsafe-output-handling"(){return require("./rules/no-unsafe-output-handling").noUnsafeOutputHandling},get"require-tool-confirmation"(){return require("./rules/require-tool-confirmation").requireToolConfirmation},get"no-system-prompt-leak"(){return require("./rules/no-system-prompt-leak").noSystemPromptLeak},get"require-embedding-validation"(){return require("./rules/require-embedding-validation").requireEmbeddingValidation},get"require-output-validation"(){return require("./rules/require-output-validation").requireOutputValidation},get"require-max-tokens"(){return require("./rules/require-max-tokens").requireMaxTokens},get"require-max-steps"(){return require("./rules/require-max-steps").requireMaxSteps},get"require-abort-signal"(){return require("./rules/require-abort-signal").requireAbortSignal},get"no-dynamic-system-prompt"(){return require("./rules/no-dynamic-system-prompt").noDynamicSystemPrompt},get"require-tool-schema"(){return require("./rules/require-tool-schema").requireToolSchema},get"no-hardcoded-api-keys"(){return require("./rules/no-hardcoded-api-keys").noHardcodedApiKeys},get"require-output-filtering"(){return require("./rules/require-output-filtering").requireOutputFiltering},get"require-rag-content-validation"(){return require("./rules/require-rag-content-validation").requireRagContentValidation},get"require-error-handling"(){return require("./rules/require-error-handling").requireErrorHandling},get"require-audit-logging"(){return require("./rules/require-audit-logging").requireAuditLogging}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-vercel-ai-security",exports.rules);exports.plugin={meta:{name:"eslint-plugin-vercel-ai-security",version:"2.1.2"},rules:exports.rules};const minimalConfig={plugins:{"vercel-ai-security":exports.plugin},rules:{"vercel-ai-security/require-validated-prompt":"error","vercel-ai-security/no-hardcoded-api-keys":"error"}};const recommendedConfig={plugins:{"vercel-ai-security":exports.plugin},rules:{"vercel-ai-security/require-validated-prompt":"error","vercel-ai-security/no-hardcoded-api-keys":"error","vercel-ai-security/no-unsafe-output-handling":"error","vercel-ai-security/no-sensitive-in-prompt":"error","vercel-ai-security/no-system-prompt-leak":"error","vercel-ai-security/no-dynamic-system-prompt":"error","vercel-ai-security/require-tool-confirmation":"error","vercel-ai-security/require-tool-schema":"error","vercel-ai-security/require-max-tokens":"error","vercel-ai-security/require-max-steps":"error","vercel-ai-security/require-output-filtering":"warn","vercel-ai-security/require-rag-content-validation":"warn","vercel-ai-security/no-training-data-exposure":"warn","vercel-ai-security/require-request-timeout":"warn","vercel-ai-security/require-error-handling":"off","vercel-ai-security/require-abort-signal":"error","vercel-ai-security/require-audit-logging":"off","vercel-ai-security/require-embedding-validation":"off","vercel-ai-security/require-output-validation":"off"}};const strictConfig={plugins:{"vercel-ai-security":exports.plugin},rules:{"vercel-ai-security/require-validated-prompt":"error","vercel-ai-security/no-hardcoded-api-keys":"error","vercel-ai-security/no-unsafe-output-handling":"error","vercel-ai-security/no-sensitive-in-prompt":"error","vercel-ai-security/no-system-prompt-leak":"error","vercel-ai-security/no-dynamic-system-prompt":"error","vercel-ai-security/require-tool-confirmation":"error","vercel-ai-security/require-tool-schema":"error","vercel-ai-security/require-max-tokens":"error","vercel-ai-security/require-max-steps":"error","vercel-ai-security/require-output-filtering":"error","vercel-ai-security/require-rag-content-validation":"error","vercel-ai-security/no-training-data-exposure":"error","vercel-ai-security/require-request-timeout":"error","vercel-ai-security/require-embedding-validation":"error","vercel-ai-security/require-output-validation":"error","vercel-ai-security/require-error-handling":"error","vercel-ai-security/require-abort-signal":"error","vercel-ai-security/require-audit-logging":"warn"}};exports.configs={flagship:{plugins:{"vercel-ai-security":exports.plugin},rules:{"vercel-ai-security/no-unsafe-output-handling":"error"}},minimal:minimalConfig,recommended:recommendedConfig,strict:strictConfig};exports.default=exports.plugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noUnsafeOutputHandling=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const vercel_ai_evidence_1=require("../../utils/vercel-ai-evidence");exports.noUnsafeOutputHandling=(0,eslint_devkit_1.createRule)({name:"no-unsafe-output-handling",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-vercel-ai-security/docs/rules/no-unsafe-output-handling.md",description:"Prevent using AI output directly in dangerous operations (eval, SQL, HTML)",cwe:"CWE-94",cvss:9.8,confidence:"medium"},messages:{unsafeOutputExecution:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"AI Output Used in Code Execution",cwe:"CWE-94",owasp:"A03:2021",cvss:9.8,description:'AI-generated content "{{variable}}" passed to {{function}}. This can lead to Remote Code Execution.',severity:"CRITICAL",compliance:["SOC2","PCI-DSS"],fix:"Never execute AI-generated code directly. Use sandboxed execution with validation.",documentationLink:"https://owasp.org/www-project-top-10-for-large-language-model-applications/"}),unsafeOutputInSQL:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"AI Output in SQL Query",cwe:"CWE-89",owasp:"A03:2021",cvss:9,description:"AI-generated content used in SQL query. Use parameterized queries instead.",severity:"CRITICAL",compliance:["SOC2","PCI-DSS"],fix:'Use parameterized queries: db.query("SELECT * FROM users WHERE id = ?", [aiOutput])',documentationLink:"https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"}),unsafeOutputInHTML:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"AI Output in innerHTML",cwe:"CWE-79",owasp:"A03:2021",cvss:7.5,description:"AI-generated content assigned to innerHTML. This can lead to XSS attacks.",severity:"HIGH",compliance:["SOC2"],fix:"Use textContent or sanitize HTML: element.textContent = aiOutput",documentationLink:"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html"})},schema:[{type:"object",properties:{aiOutputPatterns:{type:"array",items:{type:"string"},description:"Variable patterns that suggest AI output"}},additionalProperties:false}]},defaultOptions:[{aiOutputPatterns:["result.text","response.text","completion","generated","aiOutput","aiResponse","llmOutput","llmResponse","modelOutput","textContent",".text"]}],create(context){if(!(0,vercel_ai_evidence_1.fileUsesVercelAi)(context.sourceCode.ast))return{};const[options={}]=context.options;const aiOutputPatterns=options.aiOutputPatterns??["result.text","response.text","completion","generated","aiOutput","aiResponse","llmOutput",".text"];const sourceCode=context.sourceCode;const dangerousFunctions=["eval","Function","execSync","exec","spawn","execFile"];const sqlPatterns=["query","execute","run","raw"];const aiBoundVariables=new Set;function isAIBound(node){if(node.type!=="Identifier")return false;for(const variable of aiBoundVariables){if(variable.references.some(r=>r.identifier===node))return true}return false}const AI_SDK_CALLS=new Set(["generateText","streamText","generateObject","streamObject"]);function isAISDKCall(node){let target=node;if(target.type==="AwaitExpression")target=target.argument;if(target.type!=="CallExpression")return false;const callee=target.callee;if(callee.type==="Identifier"&&AI_SDK_CALLS.has(callee.name))return true;if(callee.type==="MemberExpression"&&
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noUnsafeOutputHandling=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const vercel_ai_evidence_1=require("../../utils/vercel-ai-evidence");exports.noUnsafeOutputHandling=(0,eslint_devkit_1.createRule)({name:"no-unsafe-output-handling",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-vercel-ai-security/docs/rules/no-unsafe-output-handling.md",description:"Prevent using AI output directly in dangerous operations (eval, SQL, HTML)",cwe:"CWE-94",cvss:9.8,confidence:"medium"},messages:{unsafeOutputExecution:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"AI Output Used in Code Execution",cwe:"CWE-94",owasp:"A03:2021",cvss:9.8,description:'AI-generated content "{{variable}}" passed to {{function}}. This can lead to Remote Code Execution.',severity:"CRITICAL",compliance:["SOC2","PCI-DSS"],fix:"Never execute AI-generated code directly. Use sandboxed execution with validation.",documentationLink:"https://owasp.org/www-project-top-10-for-large-language-model-applications/"}),unsafeOutputInSQL:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"AI Output in SQL Query",cwe:"CWE-89",owasp:"A03:2021",cvss:9,description:"AI-generated content used in SQL query. Use parameterized queries instead.",severity:"CRITICAL",compliance:["SOC2","PCI-DSS"],fix:'Use parameterized queries: db.query("SELECT * FROM users WHERE id = ?", [aiOutput])',documentationLink:"https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"}),unsafeOutputInHTML:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"AI Output in innerHTML",cwe:"CWE-79",owasp:"A03:2021",cvss:7.5,description:"AI-generated content assigned to innerHTML. This can lead to XSS attacks.",severity:"HIGH",compliance:["SOC2"],fix:"Use textContent or sanitize HTML: element.textContent = aiOutput",documentationLink:"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html"})},schema:[{type:"object",properties:{aiOutputPatterns:{type:"array",items:{type:"string"},description:"Variable patterns that suggest AI output"}},additionalProperties:false}]},defaultOptions:[{aiOutputPatterns:["result.text","response.text","completion","generated","aiOutput","aiResponse","llmOutput","llmResponse","modelOutput","textContent",".text"]}],create(context){if(!(0,vercel_ai_evidence_1.fileUsesVercelAi)(context.sourceCode.ast))return{};const[options={}]=context.options;const aiOutputPatterns=options.aiOutputPatterns??["result.text","response.text","completion","generated","aiOutput","aiResponse","llmOutput",".text"];const sourceCode=context.sourceCode;const dangerousFunctions=["eval","Function","execSync","exec","spawn","execFile"];const sqlPatterns=["query","execute","run","raw"];const aiBoundVariables=new Set;function isAIBound(node){if(node.type!=="Identifier")return false;for(const variable of aiBoundVariables){if(variable.references.some(r=>r.identifier===node))return true}return false}const AI_SDK_CALLS=new Set(["generateText","streamText","generateObject","streamObject"]);function isAISDKCall(node){let target=node;if(target.type==="AwaitExpression")target=target.argument;if(target.type!=="CallExpression")return false;const callee=target.callee;if(callee.type==="Identifier"&&AI_SDK_CALLS.has(callee.name))return true;if(callee.type==="MemberExpression"&&(0,eslint_devkit_1.namesOneOf)((0,eslint_devkit_1.propertyName)(callee),AI_SDK_CALLS))return true;return false}function isLikelyAIOutput(node){if(node.type==="MemberExpression"&&isAIBound(node.object)){return true}if(isAIBound(node)){return true}const text=sourceCode.getText(node);return aiOutputPatterns.some(pattern=>text.includes(pattern))}function containsAIOutput(node){if(node.type==="TemplateLiteral"){return node.expressions.some(containsAIOutput)}if(node.type==="BinaryExpression"){return node.operator==="+"&&(containsAIOutput(node.left)||containsAIOutput(node.right))}return isLikelyAIOutput(node)}return{VariableDeclarator(node){if(!node.init||!isAISDKCall(node.init))return;for(const variable of sourceCode.getDeclaredVariables(node)){aiBoundVariables.add(variable)}},CallExpression(node){const callee=sourceCode.getText(node.callee);const isDangerous=dangerousFunctions.some(fn=>callee.includes(fn));if(isDangerous){for(const arg of node.arguments){if(isLikelyAIOutput(arg)){context.report({node:arg,messageId:"unsafeOutputExecution",data:{variable:sourceCode.getText(arg),function:callee}})}}}const isSQLFunction=sqlPatterns.some(fn=>callee.includes(fn));if(isSQLFunction){for(const arg of node.arguments){if(arg.type==="TemplateLiteral"||arg.type==="BinaryExpression"){if(containsAIOutput(arg)){context.report({node:arg,messageId:"unsafeOutputInSQL"})}}}}},AssignmentExpression(node){if(node.left.type==="MemberExpression"){const prop=node.left.property;if(prop.type==="Identifier"&&prop.name==="innerHTML"){if(isLikelyAIOutput(node.right)){context.report({node:node.right,messageId:"unsafeOutputInHTML"})}}}}}}});
|