Whatever message this page gives is out now! Go check it out!

Guardrails

Last update:
May 18, 2026
Protect your RAG pipeline at both ends. ColdFusion guardrails let you intercept user messages before retrieval and model responses before delivery, blocking PII, enforcing content policy, and steering uncertain answers, all through a simple CFC validate() contract.
Guardrails sit around the chat path of a RAG service. Input guardrails inspect userMessage (and similar) before the pipeline spends work on retrieval and the LLM, useful for PII/secret blocking, length limits, or policy checks. Output guardrails inspect the model's reply before it is delivered, useful for profanity, uncertainty phrasing, or downstream compliance.

Why guardrails matter (PII, sensitive data, policy enforcement)

Guardrails are configured as arrays on the same service struct you use for CHATMODEL, ingestion, and retrievalAugmentor. They intercept every chat() call at two points: before retrieval (input) and before the answer is returned (output).
Guardrails serve three primary purposes:
  • PII and secret blocking- prevent sensitive data (SSNs, credit card numbers, passwords) from entering the pipeline or appearing in responses.
  • Policy enforcement- apply length limits, content filters, or domain restrictions before the LLM is invoked.
  • Output compliance- detect profanity, uncertainty phrasing, or answers that don't meet downstream standards before delivery.
    The pattern for configuring multiple input and output CFCs is:
ragService = agent({
  CHATMODEL: chatModel,
  ingestion: {
    source: expandPath("./test.txt"),
    documentSplitter: { chunkSize: 500, chunkOverlap: 100 },
    vectorStoreIngestor: { vectorStore: vectorStore }
  },
  retrievalAugmentor: {
    queryRouter: {
      contentRetrievers: [{
        vectorStore: vectorStore,
        maxResults: 3,
        minScore: 0.6,
        description: "Knowledge base"
      }]
    }
  },
  INPUTGUARDRAILS: [
    expandPath("./guardrails/PasswordDetectionGuardrail.cfc"),
    expandPath("./guardrails/LengthCheckGuardrail.cfc")
  ],
  OUTPUTGUARDRAILS: [
    expandPath("./guardrails/ProfanityOutputGuardrail.cfc"),
    expandPath("./guardrails/AlwaysSuccessOutputGuardrail.cfc")
  ]
});
ragService.ingest();
answer = ragService.chat("How was the state of the economy in 2025?");

Input guardrails (userMessage inspection))

Input guardrails run before the pipeline spends work on retrieval and the LLM. Each CFC in the INPUTGUARDRAILS array implements validate(required string userMessage) and returns a result struct.
// guardrails/AlwaysSuccessInputGuardrail.cfc
component {
  public struct function validate(required string userMessage) {
    return {
      result: "success",
      message: "Input is valid",
      repromptMessage: ""
    };
  }
}
Sensitive data blocked with fatal (SensitiveDataGuardrail.cfc). This guard scans for SSN, social security, credit card, and password keywords:
// guardrails/SensitiveDataGuardrail.cfc
component {
  public struct function validate(required string userMessage) {
    var patterns = ["ssn", "social security", "credit card", "password"];
    for (var pattern in patterns) {
      if (findNoCase(pattern, arguments.userMessage)) {
        return {
          result: "fatal",
          message: "Sensitive data detected: " & pattern,
          repromptMessage: ""
        };
      }
    }
    return {
      result: "success",
      message: "No sensitive data",
      repromptMessage: ""
    };
  }
}
Note: Input guardrails use the parameter name userMessage. The CFC's validate() method receives the user's raw message exactly as typed.

Output guardrails (aiMessage Inspection)

Output guardrails inspect the model's reply before it is delivered. Each CFC in the OUTPUTGUARDRAILS array implements validate(required string aiMessage) and returns a result struct.
Always-allow output (AlwaysSuccessOutputGuardrail.cfc):
// guardrails/AlwaysSuccessOutputGuardrail.cfc
component {
  public struct function validate(required string aiMessage) {
    return {
      result: "success",
      message: "Output is valid",
      repromptMessage: ""
    };
  }
}
Note: Output guardrails use the parameter name aiMessage (not userMessage). The CFC's validate() method receives the model's generated response text.

Guardrail CFC contract: validate() and return shape

A guardrail component implements validate(required string …) and returns a struct with at least the following keys:
Key
Role
result
One of three values:
• success: allow the message through.
• fatal: hard block (e.g. sensitive data).
• failure: block with guardrail failure path.
message
Human-readable reason (surfaced in errors such as "The AI request could not be completed…").
repromptMessage
Optional text for follow-up / refinement scenarios (used in some output cases).
The parameter name differs by guardrail type: input guardrails use userMessage; output guardrails use aiMessage.
component {
  public struct function validate(required string userMessage) { // or aiMessage
    // Your validation logic here
    return {
      result: "success",   // "success" | "fatal" | "failure"
      message: "Reason",
      repromptMessage: ""  // Optional — used in reprompt scenarios
    };
  }
}

Result types: success, fatal, failure, repromptMessage

Result type
Applies to
Behavior
success
Input and output
The guardrail allows the message through. Execution continues to the next guardrail in the array, or proceeds to the pipeline if this was the last.
fatal
Input and output
Hard block. The pipeline stops immediately. The message value is surfaced in the error (e.g. "The AI request could not be completed…"). Use for sensitive data, PII, or policy-critical violations where no recovery is appropriate.
failure
Input and output
Block with guardrail failure path. Stops execution and surfaces message. Less severe than fatal; used for recoverable policy violations such as excessive length or profanity.
repromptMessage
Primarily output
Optional text returned alongside failure to steer the model toward a better answer (e.g. "Provide a definitive answer based on the available data."). Exact runtime behavior depends on API version and whether reprompt flows are active.
When to use each result type
  • Use success when the message passes all checks and no action is required.
  • Use fatal for absolute blocks — PII detection, secrets, or sensitive keywords where the request must never reach the LLM.
  • Use failure for soft blocks — policy violations that are logged or surfaced but may be handled differently by the caller.
  • Set a non-empty repromptMessage on output guardrails when you want to guide the model toward a better response, such as removing uncertainty language.

Common use cases

Input: Password keyword detection (fatal)
PasswordDetectionGuardrail.cfc blocks any message containing the word "password". Returns fatal to hard-stop the pipeline:
// guardrails/PasswordDetectionGuardrail.cfc
component {
  public struct function validate(required string userMessage) {
    if (findNoCase("password", arguments.userMessage)) {
      return {
        result: "fatal",
        message: "Password detected",
        repromptMessage: ""
      };
    }
    return {
      result: "success",
      message: "No password",
      repromptMessage: ""
    };
  }
}
Input: Excessive length check (failure)
LengthCheckGuardrail.cfc rejects messages over 2000 characters with failure:
// guardrails/LengthCheckGuardrail.cfc
component {
  public struct function validate(required string userMessage) {
    if (len(arguments.userMessage) > 2000) {
      return {
        result: "failure",
        message: "Too long",
        repromptMessage: ""
      };
    }
    return {
      result: "success",
      message: "Length OK",
      repromptMessage: ""
    };
  }
}
Input: Short message check (fatal, strict)
ShortInputGuardrail.cfc blocks messages under 10 characters with fatal; useful when very short inputs would produce low-quality retrieval:
// guardrails/ShortInputGuardrail.cfc
component {
  public struct function validate(required string userMessage) {
    if (len(trim(arguments.userMessage)) < 10) {
      return {
        result: "fatal",
        message: "Message too short - please provide a detailed query",
        repromptMessage: ""
      };
    }xt
    return {
      result: "success",
      message: "Input is valid",
      repromptMessage: ""
    };
  }
}
Output: Profanity detection (failure)
Profanity and uncertainty phrases are modeled in CFCs. ProfanityOutputGuardrail.cfc checks for a keyword (example: "badword") and returns failure:
// guardrails/ProfanityOutputGuardrail.cfc
component {
  public struct function validate(required string aiMessage) {
    if (findNoCase("badword", arguments.aiMessage) > 0) {
      return {
        result: "failure",
        message: "Profanity detected in output",
        repromptMessage: ""
      };
    }
    return {
      result: "success",
      message: "Output is clean",
      repromptMessage: ""
    };
  }
}
Output: Uncertainty markers with repromptMessage
Uncertainty detection returns failure and sets repromptMessage to steer a more definitive answer (exact runtime behavior may wrap this in your product's error/reprompt flow). UncertaintyOutputGuardrail.cfc checks for markers such as "i think", "maybe", "possibly", "not sure", and "probably":
// guardrails/UncertaintyOutputGuardrail.cfc
component {
  public struct function validate(required string aiMessage) {
    var markers = ["i think", "maybe", "possibly", "not sure", "probably"];
    for (var marker in markers) {
      if (findNoCase(marker, arguments.aiMessage)) {
        return {
          result: "failure",
          message: "Response contains uncertainty",
          repromptMessage: "Provide a definitive answer based on the available data."
        };
      }
    }
    return {
      result: "success",
      message: "Response is definitive",
      repromptMessage: ""
    };
  }
}

Chain guardrails and execution order

Input guardrails run in array order. The execution-order test appends A, then B, then C to application.guardrailOrder and expects the string ABC.
Order tracking
Each component in the chain appends its letter to application.guardrailOrder and returns success. This pattern lets you verify execution order.
// guardrails/OrderTrackerInputGuardrailA.cfc
component {
  public struct function validate(required string userMessage) {
    application.guardrailOrder = (structKeyExists(application, "guardrailOrder")
      ? application.guardrailOrder : "") & "A";
    return {
      result: "success",
      message: "Guard A passed",
      repromptMessage: ""
    };
  }
}
Wiring the three ordered guards:
INPUTGUARDRAILS: [
  expandPath("./guardrails/OrderTrackerInputGuardrailA.cfc"),
  expandPath("./guardrails/OrderTrackerInputGuardrailB.cfc"),
  expandPath("./guardrails/OrderTrackerInputGuardrailC.cfc")
]
Mixed chain
A mixed chain of AlwaysSuccessInputGuardrail, RepromptInputGuardrail, and AlwaysFailInputGuardrail demonstrates that a later guard can fail after earlier guards succeed.
RepromptInputGuardrail.cfc returns failure when the message is shorter than 10 characters:
// guardrails/RepromptInputGuardrail.cfc
component {
  public struct function validate(required string userMessage) {
    if (len(trim(arguments.userMessage)) < 10) {
      return {
        result: "failure",
        message: "Message too short - please provide a detailed query",
        repromptMessage: ""
      };
    }
    return {
      result: "success",
      message: "Input is valid",
      repromptMessage: ""
    };
  }
}
AlwaysFailInputGuardrail.cfc always returns failure regardless of input. It is useful for testing that a later guard in the chain can block even when earlier guards passed:
// guardrails/AlwaysFailInputGuardrail.cfc
component {
  public struct function validate(required string userMessage) {
    return {
      result: "failure",
      message: "Guard blocks this",
      repromptMessage: ""
    };
  }
}
Execution order rules
  • Guardrails in INPUTGUARDRAILS run in array index order, left to right, before retrieval and LLM invocation.
  • Guardrails in OUTPUTGUARDRAILS run in array index order after the LLM generates its response, before delivery.
  • If any guardrail returns fatal or failure, execution stops at that guard, subsequent guards in the array do not run.
  • A success result advances execution to the next guardrail in the array.
  • If all guardrails return success, the message or response is allowed through to the next pipeline stage.

Share this page

Was this page helpful?
We're glad. Tell us how this page helped.
We're sorry. Can you tell us what didn't work for you?
Thank you for your feedback. Your response will help improve this page.

On this page