""" Input sanitization / prompt-injection hygiene. The user's product description and target keywords are untrusted input. Before they go anywhere near the LLM prompt, strip out patterns that look like an attempt to override the system prompt. This is defense-in-depth, not a silver bullet: it reduces the surface for naive injection attempts. It does not replace treating LLM output as untrusted too (see llm/validation.py, which never trusts the model's claims about its own compliance and re-checks everything in code). """ import re # Patterns commonly used to try to hijack a system prompt. Case-insensitive. _INJECTION_PATTERNS = [ r"ignore (all |any )?(previous|prior|above|the) (instructions?|prompts?)", r"disregard (all |any )?(previous|prior|above|the) (instructions?|prompts?)", r"forget (all |any )?(previous|prior|above|the) (instructions?|prompts?)", r"you are now", r"new system prompt", r"system\s*:", r"assistant\s*:", r"\bact as\b", r"reveal (your|the) (system )?prompt", r"", r"\[/?INST\]", ] _COMPILED = [re.compile(p, re.IGNORECASE) for p in _INJECTION_PATTERNS] _REDACTION_MARKER = "[removed]" # Hard cap on how much raw text we'll even consider from the user, to keep # prompts small and bound worst-case cost/latency. MAX_INPUT_CHARS = 2000 def sanitize_user_input(text: str | None) -> str: """Strip likely prompt-injection attempts and cap length. Returns an empty string for None/blank input. """ if not text: return "" text = text.strip()[:MAX_INPUT_CHARS] for pattern in _COMPILED: text = pattern.sub(_REDACTION_MARKER, text) # Strip characters sometimes used to fake role-turn boundaries. text = text.replace("```", "'''") return text.strip() def redact_for_logs(*_args, **_kwargs) -> str: """Logs must never contain full user-submitted text or PII (email etc.). Anywhere we'd be tempted to log the raw product_description, email, or LLM output, log this placeholder + a request id instead. Kept as an explicit function (rather than just "don't log it") so call sites are self-documenting about *why* the value is missing from logs. """ return "[redacted]"