Untrusted Input Reaching Your Prompt
Explore prompt injection, a security risk where untrusted input manipulates AI model instructions in backend prompts. Understand why validation alone cannot detect manipulation and how architectural strategies that treat model output strictly as data help maintain system safety and reliability. This lesson guides you through recognizing prompt injection and implementing effective mitigations.
Every prompt built across this course has embedded customer-supplied text directly into the prompt instructions. This pattern is common and relatively low risk in simple tasks such as feedback analysis. It becomes a security risk when someone intentionally crafts the input to override or interfere with the intended instructions. This lesson introduces prompt injection as that risk and demonstrates a core practice for reducing it.
Setup code
The block below is carried over so this file runs entirely on its own: the schema a valid result must match, the prompt builder, and the routing function built earlier in this course. This lesson needs both, since the whole point is watching a manipulated response still pass through them exactly as any other result would.
from enum import Enumfrom pydantic import BaseModel, Field, ValidationErrorclass Sentiment(str, Enum):POSITIVE = "positive"NEUTRAL = "neutral"NEGATIVE = "negative"class FeedbackCategory(str, Enum):PRODUCT_QUALITY = "product_quality"CUSTOMER_SERVICE = "customer_service"PRICING = "pricing"OTHER = "other"class Confidence(str, Enum):HIGH = "high"LOW = "low"class Feedback(BaseModel):sentiment: Sentimentcategory: FeedbackCategoryseverity: int = Field(ge=1, le=5, default=1)confidence: Confidencesummary: strdef build_feedback_prompt(feedback_text: str) -> str:return ("Analyze the customer feedback below. Respond with a JSON object ""in exactly this shape, and nothing else:\n\n""{\n"' "sentiment": <one of: "positive", "neutral", "negative">,\n'' "category": <one of: "product_quality", "customer_service", ''"pricing", "other">,\n'' "severity": <integer from 1 to 5>,\n'' "confidence": <one of: "high", "low">,\n'' "summary": <string, one short sentence>\n'"}\n\n"f'Feedback: "{feedback_text}"')def create_ticket(feedback: Feedback) -> None:print(f"Creating ticket. Category: {feedback.category.value}. Summary: {feedback.summary}")def notify_channel(feedback: Feedback) -> None:print(f"Notifying #feedback channel. Summary: {feedback.summary}")def archive_silently(feedback: Feedback) -> None:print(f"Archived with no action. Category: {feedback.category.value}.")def route_feedback(feedback: Feedback) -> str:if feedback.confidence == Confidence.LOW:notify_channel(feedback)return "notified_low_confidence"if feedback.severity >= 4:create_ticket(feedback)return "ticket_created"if feedback.severity >= 2:notify_channel(feedback)return "notified"archive_silently(feedback)return "archived"
What prompt injection actually is
Prompt injection is what happens when untrusted input, text we did not write and cannot fully control, contains something that looks like an instruction, and the model follows that instruction instead of, or alongside, the one we actually intended. It is not a bug in a specific provider's SDK, and it is not something a cleverer prompt fully closes off. It follows directly from something established earlier in this course: a system prompt shapes behavior; it does not guarantee it. If shaping behavior with our own instructions is never fully guaranteed, then text embedded inside that same request has a real, if often small, chance of shaping behavior too, whether we intended it to or not.
The block below shows both halves of the problem at ...