Guardrails and Safety
Implement content moderation, PII redaction, output schema guardrails, and refusal cascades for safe AI deployment.
TL;DR
- Screen toxic user inputs and completions using OpenAI
moderations.create()APIs. - Redact sensitive personally identifiable information via regex
maskPII()filters. - Validate generated outputs against strict type schemas using
zodbefore delivery.
OpenAI Moderation API
Content Moderation ScreenDetect hate, harassment, self-harm, and violence.
import OpenAI from 'openai';
const client = new OpenAI();
async function isFlagged(
input: string
): Promise<boolean> {
const mod = await client.moderations.create({
model: 'omni-moderation-latest',
input,
});
return mod.results[0]?.flagged ?? false;
}Category Score Threshold GateFlag inputs exceeding custom safety score thresholds.
function checkHarassmentScore(
result: any, maxScore = 0.5
) {
const scores = result.category_scores;
if (scores.harassment > maxScore) {
const err = 'Input exceeds harassment threshold';
throw new Error(err);
}
}Dual Input-Output Moderation GateModerate both incoming user prompt and outgoing model reply.
async function safeTurn(userInput: string) {
if (await isFlagged(userInput)) {
throw new Error('Unsafe user input');
}
const answer = await callLLM(userInput);
if (await isFlagged(answer)) {
throw new Error('Unsafe model answer');
}
return answer;
}Personally Identifiable Information (PII) Redaction
Regex Pattern PII RedactorMask emails, phone numbers, and SSNs with placeholder tokens.
function redactPII(text: string): string {
const EMAIL_RE = /[^@\s]+@[^@\s]+\.[^@\s]+/g;
const PHONE_RE = /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g;
return text
.replace(EMAIL_RE, '[EMAIL]')
.replace(PHONE_RE, '[PHONE]')
.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN]');
}Credit Card Luhn Algorithm RedactorDetect and mask valid credit card numbers in text strings.
function redactCreditCards(text: string): string {
const CARD_RE = /\b(?:\d[ -]*?){13,16}\b/g;
return text.replace(CARD_RE, '[CARD]');
}PII Audit LoggerRecord redaction event without logging raw sensitive values.
function logRedactionEvent(type: string) {
securityMetrics.increment(
'pii_redacted', 1, { type }
);
}Output Schema Guardrails with Zod
Strict Output Schema AssertionEnforce domain constraints on generated JSON outputs.
import { z } from 'zod';
const SafeOutputSchema = z.object({
recommendation: z.string().max(200),
riskLevel: z.enum(['low', 'medium', 'high']),
confidence: z.number().min(0).max(1),
});
function validateOutput(rawJson: string) {
return SafeOutputSchema.parse(JSON.parse(rawJson));
}HTML Injection SanitizerEscape HTML tags to prevent cross-site scripting (XSS).
function escapeHtml(str: string) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}Schema Retry Fallback HandlerRetry request with schema correction when output validation fails.
async function getWithRetry(q: string, attempts = 2) {
for (let i = 0; i < attempts; i++) {
try {
const raw = await callLLM(q);
return validateOutput(raw);
} catch (e) { /* retry */ }
}
throw new Error('Failed schema validation');
}Refusal Cascades & Policy Management
Graceful Refusal FormatterDeliver empathetic and helpful policy refusal messages.
function formatRefusal(reason: string) {
const msg = `Cannot assist with ${reason}.`;
return {
success: false,
message: msg,
alternative: 'Can help with general info.',
};
}Topic Blocklist GuardIntercept forbidden operational topics before LLM dispatch.
const BANNED_TOPICS = [
'medical_advice', 'crypto_speculation',
];
function checkTopic(topic: string) {
if (BANNED_TOPICS.includes(topic)) {
return formatRefusal(topic);
}
}Safety Telemetry Incident HookLog safety violation events for compliance audits.
function recordSafetyViolation(
cat: string, usr: string
) {
complianceLogger.warn('policy_violation', {
category: cat,
userId: usr,
timestamp: new Date().toISOString(),
});
}Tips
- Execute
omni-moderation-latestchecks asynchronously on streaming tokens to catch safety violations without inflating initial Time-to-First-Token latency. - Mask credit cards and Social Security numbers using client-side
regexfilters prior to transmitting prompts across provider network boundaries.
Warnings
- Never display unvalidated LLM output containing user-generated HTML directly in browsers without strict HTML
escaping. - Avoid hardcoded naive keyword blocklists that produce frequent false positive refusals on legitimate medical or technical
inquiries.
In Practice
Screens input via OpenAI Moderation, redacts sensitive PII, executes generation, and validates output structure.
- Check user input against OpenAI Moderation API.
- Mask sensitive phone numbers and emails with regex.
- Invoke model with structured prompt instructions.
- Validate final response complies with safety schema.
import OpenAI from 'openai';
import { z } from 'zod';
const client = new OpenAI();
const OutSchema = z.object({ answer: z.string() });
async function safePipeline(input: string) {
const mod = await client.moderations.create({
input, model: 'omni-moderation-latest',
});
if (mod.results[0]?.flagged) throw new Error('Bad');
const clean = input.replace(/\d{3}-\d{4}/g, '[P]');
const r = await client.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: clean }],
response_format: { type: 'json_object' },
});
const txt = r.choices[0]?.message?.content ?? '{}';
return OutSchema.parse(JSON.parse(txt));
}
console.log(await safePipeline('Call 555-0199'));FAQ
The OpenAI Moderation API is completely free to use for developers using OpenAI services, making it an essential zero-cost defense layer.
It flags hate speech, harassment, self-harm, sexual content, violence, and dangerous weapons, providing category flags and confidence scores.
Provide a neutral, respectful canned explanation explaining that the query touches restricted topics, and offer constructive alternative inquiries.