Search⌘ K
AI Features

Untrusted Input Reaching Your Prompt

Explore the challenge of prompt injection when untrusted user input is embedded in AI prompts. Understand why prompt injection is a security risk unique to AI systems and why treating model output strictly as data is key. Learn practical architectural defenses that ensure prompt manipulation cannot cause unintended actions, enhancing AI backend reliability.

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 Enum
from pydantic import BaseModel, Field, ValidationError
class 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: Sentiment
category: FeedbackCategory
severity: int = Field(ge=1, le=5, default=1)
confidence: Confidence
summary: str
def 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 ...