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

require-output-filtering

This rule identifies tool execute functions that return raw data from data sources (databases, APIs, file systems) wi...

Requires filtering of sensitive data returned by AI tools.

📊 Rule Details

PropertyValue
Typesuggestion
Severity🟡 HIGH
OWASP AgenticASI04: Data Exfiltration
CWECWE-200: Information Exposure
CVSS6.5
Config Defaultoff (recommended), error (strict)

🔍 What This Rule Detects

This rule identifies tool execute functions that return raw data from data sources (databases, APIs, file systems) without filtering potentially sensitive information.

❌ Incorrect Code

// Direct database query return
const tools = {
  search: {
    execute: async ({ sql }) => db.query(sql),
  },
};

// Direct find operation
const tools = {
  getUser: {
    execute: async ({ id }) => users.findById(id),
  },
};

// Raw fetch result
const tools = {
  loadData: {
    execute: async ({ url }) => fetchData(url),
  },
};

✅ Correct Code

// Filtered database results
const tools = {
  search: {
    execute: async ({ sql }) => filterSensitive(db.query(sql)),
  },
};

// Sanitized user data
const tools = {
  getUser: {
    execute: async ({ id }) => sanitizeUserData(users.findById(id)),
  },
};

// Filtered fetch result
const tools = {
  loadData: {
    execute: async ({ url }) => {
      const data = await fetchData(url);
      return removePII(data);
    },
  },
};

⚙️ Options

OptionTypeDefaultDescription
dataSourcePatternsstring[]["query","find","select","aggregate","database","db","sql","mongo","prisma","supabase"]Patterns suggesting data sources
filterFunctionsstring[]["filter","sanitize","redact","mask","clean","filterSensitive","removePII","scrub"]Functions considered safe filters

🛡️ Why This Matters

Unfiltered tool output can expose:

  • PII - Names, emails, addresses, SSNs
  • Credentials - Passwords, tokens, API keys
  • Internal data - Database IDs, internal URLs
  • Business data - Financial records, contracts

🔄 Changes in the 2026-10-10 FP/FN audit

  • A data source is a member call whose call chain has a data-access word (db.user.findUnique, supabase.from('t').select, prisma.x.findMany). get, fetch, read and load were removed from the defaults: they matched getWeather(city) and the RAG guide's findRelevantContent(question).
  • Block-bodied and method-form executes are checked: a return of a data-source call, or of a variable initialised from one in the same function.
  • Now off in recommended.
  • Options: the documented defaultOptions now apply. Earlier versions read context.options and silently ran a shorter hard-coded list instead.

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Filtering in Separate Function

Why: Filtering in called functions is not recognized.

// ❌ NOT DETECTED - Filtering in getData
const tools = {
  getUser: {
    execute: async ({ id }) => getUserSafe(id), // Filters internally
  },
};

Mitigation: Document filtering. Apply rule to data access functions.

Custom Data Source Methods

Why: Non-standard data methods may not be detected.

// ❌ NOT DETECTED - Custom method name
const tools = {
  data: {
    execute: async () => myCustomDb.retrieve(id), // Not in patterns
  },
};

Mitigation: Configure dataSourcePatterns with custom method names.

Chained Method Filtering

Why: Method chaining may hide filtering status.

// ❌ NOT DETECTED - Filter in chain
const tools = {
  search: {
    execute: async () => db.query(sql).sanitize().toJSON(),
  },
};

Mitigation: Use explicit filter function calls.

Dynamic Tool Execution

Why: Dynamic execute functions are not analyzed.

// ❌ NOT DETECTED - Dynamic execute
const tools = {
  [name]: { execute: handlers[name] }, // Handler may not filter
};

Mitigation: Review all dynamic handlers for filtering.

📚 References

Use this rule

npm install -D oxlint-plugin-vercel-ai-security
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-vercel-ai-security"],  "rules": {    "vercel-ai-security/require-output-filtering": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-vercel-ai-security'],    rules: {      'vercel-ai-security/require-output-filtering': 'error',    },  },});

oxlint-plugin-vercel-ai-security re-exports eslint-plugin-vercel-ai-security/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.