Skip to main content
Validating string presence in LLM-generated content and user inputs presents unique challenges. The contains string guardrail solves these challenges through instant, deterministic pattern matching that costs nothing and responds in under 10 milliseconds.
When you need to ensure legal disclaimers appear in LLM outputs, block sensitive information in user inputs, or verify required sections exist in generated documents, you need validation that happens instantly without waiting for LLM analysis.Contains string provides sub-10ms response times with zero cost since it runs locally using simple pattern matching. This makes it perfect as a front-line filter before more expensive LLM-powered guardrails.

How Contains String Works

Understanding the validation process helps you choose the right mode and configure effective string lists:

Content submission with configuration

You send text to the contains string guardrail along with your configuration: a list of strings to check for, which mode to use (ANY, ALL, or NONE), and optionally whether to use case-sensitive matching. The configuration determines exactly how the validation behaves.

Pattern matching execution

The guardrail performs simple string matching against your content. This happens locally on ABV’s infrastructure without any LLM calls, making it instant (under 10ms) and free.ANY mode: Checks if at least one string from your list appears in the text. Passes when any match is found.ALL mode: Checks if every string from your list appears in the text. Passes only when all strings are present.NONE mode: Checks that no strings from your list appear in the text. Passes only when zero matches are found.By default, matching is case-insensitive (“Password” matches “password”). Enable case-sensitive matching when exact capitalization matters.

Deterministic result

The guardrail returns a result indicating pass or fail. Since this is rule-based validation, there’s no “unsure” status—the result is always definitive. The confidence is always 1.0 because pattern matching has no uncertainty.The reason field explains which strings were found or missing. Log this internally for debugging and analysis, but as with all guardrails, never expose detailed reasons to end users to prevent evasion learning.

Automatic observability

Every validation automatically creates an observation in ABV capturing the input text, result, configuration (strings, mode, case sensitivity), and performance metrics. This happens even though the guardrail is free to use, giving you visibility into validation patterns and helping you tune your string lists over time.

When to Use This Guardrail

Contains string excels in specific scenarios where you can enumerate exactly what to check:
Users sometimes share passwords, credit card numbers, social security numbers, or other sensitive information they shouldn’t submit to LLMs. These inputs create security risks and compliance violations.Use NONE mode to block content containing forbidden terms like “password,” “SSN,” “credit card,” and “bank account.” This pre-filtering happens instantly, blocking obvious violations before more expensive content analysis.
Generated documents, emails, and content often need specific elements for compliance or quality. Marketing emails need unsubscribe links, privacy policy links, and copyright notices. Generated contracts need specific clauses.Use ALL mode to ensure every required element appears. If any element is missing, the validation fails, preventing incomplete content from reaching users or requiring manual review.
Marketing content, product descriptions, and customer communications should avoid mentioning competitor brands. Even indirect references can violate brand guidelines or create legal issues.Use NONE mode with a comprehensive list of competitor names, product names, and domain names. The instant validation catches mentions before content is published.
When combining multiple guardrails, run the fastest checks first. Contains string costs nothing and responds in under 10ms, while LLM-powered guardrails take 1-3 seconds and consume tokens.Use contains string to catch obvious violations instantly, then only run expensive LLM-powered checks on content that passes the initial filter. This pattern dramatically reduces costs and latency.

Understanding Match Modes

The three modes fundamentally change validation behavior. Choosing the right mode is essential:

ANY Mode (OR Logic)

Behavior: Content passes when at least one string from your list appears. Use cases:
  • Legal disclaimers where multiple phrasings are acceptable
  • Detecting any of several forbidden categories
  • Ensuring at least one required element exists
// Accept any valid disclaimer phrasing
await abv.guardrails.containsString.validate(llmOutput, {
  strings: [
    "not financial advice",
    "consult a professional",
    "for informational purposes only",
    "not legal advice"
  ],
  mode: "any"
});
// Passes if ANY of these phrases appears

ALL Mode (AND Logic)

Behavior: Content passes only when every string from your list appears. Use cases:
  • Email compliance requiring unsubscribe link, privacy policy, and copyright
  • Document templates needing all required sections
  • Quality checks ensuring completeness
// Ensure all required email elements are present
await abv.guardrails.containsString.validate(emailBody, {
  strings: [
    "Unsubscribe",
    "Privacy Policy",
    "Contact Us",
    "© 2024"
  ],
  mode: "all"
});
// Passes only if ALL elements are present

NONE Mode (NOT Logic)

Behavior: Content passes only when zero strings from your list appear. Use cases:
  • Blocking sensitive information (passwords, credit cards, SSNs)
  • Preventing competitor mentions
  • Filtering forbidden terms before expensive checks
// Block sensitive information in user inputs
await abv.guardrails.containsString.validate(userMessage, {
  strings: [
    "password",
    "credit card",
    "ssn",
    "social security",
    "bank account",
    "routing number"
  ],
  mode: "none",
  caseSensitive: false  // Catch any capitalization
});
// Passes only if NONE of these terms appear

Case-Sensitive Matching

By default, matching is case-insensitive: “PASSWORD,” “Password,” and “password” all match. This catches variations in how people write. Enable case-sensitive matching when exact capitalization matters:
// Exact brand name matching
await abv.guardrails.containsString.validate(content, {
  strings: ["iPhone", "MacBook", "JavaScript"],
  mode: "any",
  caseSensitive: true  // "iphone" won't match "iPhone"
});

Implementation Patterns

Ensure LLM-generated content includes appropriate disclaimers while allowing flexibility in phrasing:
async function ensureDisclaimer(content: string): Promise<{ valid: boolean; error?: string }> {
  const result = await abv.guardrails.containsString.validate(content, {
    strings: [
      "not financial advice",
      "not legal advice",
      "consult a professional",
      "for informational purposes only"
    ],
    mode: "any"
  });

  if (result.status === "pass") {
    return { valid: true };
  }

  return {
    valid: false,
    error: "Content must include an appropriate disclaimer"
  };
}

Sensitive Information Blocking

Prevent users from sharing sensitive information that creates security and compliance risks:
async function blockSensitiveInfo(userInput: string): Promise<{ allowed: boolean; message?: string }> {
  const result = await abv.guardrails.containsString.validate(userInput, {
    strings: [
      "password", "pwd", "passcode",
      "credit card", "cc", "card number", "mastercard", "visa",
      "ssn", "social security",
      "bank account", "routing number",
      "pin", "cvv"
    ],
    mode: "none",
    caseSensitive: false
  });

  if (result.status === "pass") {
    return { allowed: true };
  }

  return {
    allowed: false,
    message: "Please don't share sensitive personal information in your message"
  };
}

Email Compliance Verification

Ensure all required elements appear in marketing emails for CAN-SPAM and other compliance:
async function validateEmailCompliance(emailBody: string): Promise<{ compliant: boolean; missing?: string[] }> {
  const requiredElements = [
    "Unsubscribe",
    "Privacy Policy",
    "Contact Us",
    "© 2024"  // Current year copyright
  ];

  const result = await abv.guardrails.containsString.validate(emailBody, {
    strings: requiredElements,
    mode: "all"
  });

  if (result.status === "pass") {
    return { compliant: true };
  }

  return {
    compliant: false,
    // In production, determine specific missing elements
    missing: requiredElements
  };
}

Efficient Pre-Filtering Pattern

Use contains string as a fast pre-filter before expensive LLM-powered guardrails:
async function efficientValidation(content: string): Promise<boolean> {
  // Fast check first: block explicitly forbidden terms (< 10ms, free)
  const quickCheck = await abv.guardrails.containsString.validate(content, {
    strings: ["explicit-slur", "forbidden-term", "banned-phrase"],
    mode: "none"
  });

  // If quick check fails, we're done - no need for expensive LLM check
  if (quickCheck.status === "fail") {
    console.log("Blocked by fast pre-filter");
    return false;
  }

  // Only run expensive LLM-powered check if content passed pre-filter
  // This saves 1-3 seconds and token costs when quick check catches issues
  const deepCheck = await abv.guardrails.toxicLanguage.validate(content);
  return deepCheck.status === "pass";
}

Building Effective String Lists

The effectiveness of contains string depends entirely on the quality of your string lists:
Cast a wide net by including variations. Rather than just “password,” include “pwd,” “pass,” “passcode,” “pw.” For credit cards, include “credit card,” “cc,” “card number,” “mastercard,” “visa,” “amex.”Pattern: Think about every reasonable way someone might express the concept, including abbreviations, common misspellings, and related terms.
Offer multiple phrasings that accomplish the same legal purpose. For financial advice disclaimers: “not financial advice,” “consult a financial professional,” “for informational purposes only,” “not investment advice.”Pattern: All variations protect you legally while giving content creators flexibility in exact wording.
Be comprehensive. Include company names, product names, domain names, and common misspellings. For “CompetitorCo”: also include “competitor-co,” “competitorco,” “competitor.com,” “CompetitorCorp.”Pattern: Cover official names, informal names, domains, and variations people actually use when mentioning competitors.
Use case-insensitive matching (default) for general terms where capitalization varies. Use case-sensitive matching for brand names (“iPhone” not “iphone”), proper nouns, and technical terms where capitalization has specific meaning (“JavaScript” vs “javascript”).Pattern: Case-sensitive when exact form matters for correctness or brand identity. Case-insensitive for broader coverage of general terms.

Combining with Other Guardrails

Contains string works particularly well as part of layered validation: Sequential filtering pipeline: Run contains string first (instant, free) to catch obvious violations, then run LLM-powered guardrails (1-3 seconds, token cost) only on content that passes. This dramatically reduces costs while maintaining comprehensive protection. With toxic language detection: Block explicitly forbidden slurs with contains string, then use toxic language detection for context-aware analysis of everything else. The contains string pre-filter catches the obvious cases instantly. With valid JSON: When LLM generates JSON, validate JSON structure first (instant), then use contains string to verify specific required fields exist before checking content quality with LLM-powered guardrails. With biased language detection: Block obviously discriminatory terms with contains string, then use biased language detection for subtle coded language and contextual bias. Two-layer protection at different speeds and costs.

Next Steps