SaveMyCert
Log in
5 of 5 free questions left today·for 30 a day
Implement computer vision solutions

AI-103: Responsible AI for Images — Content Safety, Prompt Shields and Visual Policy

18 min readAI-103 · Implement computer vision solutionsUpdated

Responsible AI for multimodal content is the set of controls that check images — those users upload and those your models generate — for harmful content, hidden instructions and policy breaches before they are processed or published. This lesson covers AI-103 task 3.3: classifying unsafe images with Azure AI Content Safety and Foundry guardrails, detecting and mitigating prompt injection carried as text inside images, and enforcing visual policy rules such as watermarks, prohibited symbols and brand usage.

What you’ll learn
  • Classify unsafe images with the Content Safety Analyze Image API, interpret the 0/2/4/6 image severity scale and set application thresholds.
  • Apply image input rules: size and dimension limits, first-frame analysis of animations, and keyless blob access through the Content Safety resource's managed identity.
  • Moderate images together with their text using the multimodal API with enableOcr, and work around its 1,000-character limits.
  • Configure Foundry guardrail content-harm controls for image inputs and generated images: intervention points, blocking levels and modified-guardrail approval.
  • Detect indirect prompt injection in image text by extracting it and checking it as a Prompt Shields document, within the request limits.
  • Design mitigations for image-borne injection and choose proportionate responses to a detection.
  • Enforce visual policy: visible watermarks vs Content Credentials, custom categories (rapid) image incidents for prohibited symbols, and Content Understanding classify fields with rules in code for brand checks.

What does responsible AI for multimodal content cover on AI-103?

Responsible AI for multimodal content means checking images — the ones users upload and the ones your models generate — for harm, hidden instructions and policy breaches before they can do damage. AI-103 task 3.3 has three skills, and each maps to a different set of tools:

SkillWhat it protects againstMain tools
Filter unsafe or disallowed visual contentSexual, violent, hateful and self-harm imageryContent Safety Analyze Image API, the multimodal image-with-text API, Foundry guardrails on image inputs and generated images
Detect and mitigate indirect prompt injection from text in imagesInstructions printed inside a photo or screenshot that try to steer a model or agentText extraction + Prompt Shields (document attacks), plus design controls such as a tool-less extraction step and human approval
Enforce visual policy rulesMissing labels, prohibited symbols, off-brand use, inappropriate contentApp-composited watermarks, Content Credentials, custom categories (rapid) image incidents, Azure Content Understanding classify fields, deterministic rules in code

A useful rule of thumb runs through the whole topic: the AI services produce signals (severities, attack flags, field values), and the application or the guardrail makes the decision. Knowing which service produces which signal, and where the decision is made, answers most design questions here.

Image generation controls and Content Understanding analyzer mechanics belong to the sibling tasks (3.1 and 3.2), and agent-wide guardrail governance belongs to Domain 1; this lesson uses them only as they apply to visual safety and policy.

How do you classify unsafe images with the Content Safety Analyze Image API?

You classify an unsafe image by sending it to the Azure AI Content Safety Analyze Image API, which returns a severity for each of four harm categories — Hate, Sexual, Violence and Self-harm — and then comparing each severity with a threshold your application chooses. The API scores; it does not block. That makes it the right tool when no generative model is in the flow, such as moderating user uploads before they are published.

The image severity scale

Text analysis can return the full 0–7 scale, but the current image model returns a trimmed scale of four values: 0, 2, 4 and 6. Each pair of adjacent levels collapses into one value:

Image severity valueLevel
0Safe
2Low
4Medium
6High

This matters when you write thresholds. Odd values such as 3 or 5 never occur for images, so a threshold written for the text scale can quietly change meaning: "reject at 3 or above" behaves exactly like "reject at 4 or above" for images, and low content (2) is allowed. Write image rules against the values that actually occur — 2, 4 and 6 — so the rule says what it does.

Calling it from Python

With the azure-ai-contentsafety package, you wrap the image in ImageData inside AnalyzeImageOptions. ImageData takes either content (the raw image bytes) or blob_url (an Azure Blob Storage URL the service reads itself):

from azure.ai.contentsafety import ContentSafetyClient
from azure.ai.contentsafety.models import AnalyzeImageOptions, ImageData

client = ContentSafetyClient(endpoint, credential)
with open(path, "rb") as f:
    request = AnalyzeImageOptions(image=ImageData(content=f.read()))
response = client.analyze_image(request)

for item in response.categories_analysis:
    print(item.category, item.severity)

Pass the raw bytes: the SDK base64-encodes them for the REST body, so encoding them yourself first corrupts the payload. A file name or local path is not something the service can fetch. In REST, the same request carries image.content as base64 or image.blobUrl, and the image response uses outputType FourSeverityLevels.

What input limits apply to image analysis?

The Analyze Image API accepts images up to 4 MB and between 50 x 50 and 7,200 x 7,200 pixels, in JPEG, PNG, GIF, BMP, TIFF or WEBP format. Requests outside those limits are rejected, so camera originals (often far larger in both bytes and pixels) must be downscaled and compressed before analysis. The limits apply to the image itself, whichever way you deliver it, so the fix is always to reduce the image: fewer pixels and lossy compression. Changing only the container or delivery method leaves an oversized image oversized.

Animated images: only the first frame

For an animated format such as an animated GIF, the service extracts the first frame and analyzes only that. A sticker or animation can therefore open with harmless frames and show harmful content later and still pass. If animations are a risk, split them in your application and send frames (every frame, or a sampling dense enough for your risk) as separate images, then combine the results — for example, take the highest severity per category.

Reading images from Blob Storage without keys

When you pass a blobUrl, the Content Safety service downloads the image itself, so it is the Content Safety resource — not your app — that needs access. To avoid SAS tokens and account keys, Microsoft documents this setup:

  1. Enable the Content Safety resource's system-assigned managed identity.
  2. Assign that identity Storage Blob Data Contributor or Storage Blob Data Owner on the storage account.

Microsoft states these are the only valid roles for this scenario — Storage Blob Data Reader looks like the least-privilege choice but is not listed, and the control-plane Reader role grants no access to blob data at all. Granting a role to your application's identity does nothing here, because the app never makes the read.

How do you moderate an image together with its text?

You moderate an image and its text together with the Content Safety multimodal (image-with-text) API, which analyzes an image plus associated text in one request and returns harm severities for the combination. Set enableOcr to true and the service also runs OCR on the image and analyzes the recognised text along with the visual content. This catches the classic meme problem: a harmless photo with a hateful caption, which Analyze Image scores as safe because it judges only the visual content.

The multimodal API has tight text limits worth remembering:

  • With enableOcr, it analyzes at most 1,000 characters of text recognised in the image; anything beyond is truncated.
  • Its optional text field is also limited to 1,000 characters.

Text-heavy images — long chat screenshots, scanned pages — can therefore hide harmful text past the first 1,000 characters. Because both text inputs share the same cap, the multimodal API alone can't cover long text. The simple fix is to keep the multimodal call for the visuals and also score the full extracted text with the Analyze Text API, which accepts up to 10,000 characters per request (split longer text into several requests).

APIWhat it judgesUse it when
Analyze ImageVisual content onlyPhotos where any text is irrelevant
Image-with-text (enableOcr)Visuals plus up to 1,000 characters of OCR or supplied text, togetherMemes, captioned images, short overlays
Analyze TextText only, up to 10,000 characters per requestLong extracted text, comments, transcripts
Prompt ShieldsAttacks (instructions), not harmText that will be fed to a model or agent
Protected material detectionKnown copyrighted text (such as lyrics or articles) or code in model output — not harm, not imagesChecking generated text or code for reproduced protected content

How do Foundry guardrails filter images going into and out of a model?

Foundry guardrails filter images by applying content-harm controls (Hate, Sexual, Violence, Self-harm) to the inputs and outputs of a model deployment or agent, including image inputs to vision-capable models and images produced by image-generation models such as the GPT-image-1 series. Unlike the standalone Content Safety APIs, a guardrail enforces the decision for you: assign it to the deployment and blocked content never reaches the model or the caller, with no moderation code in the app.

Intervention points

A guardrail control applies at one or more intervention points: user input, tool call, tool response and output. Model deployments use user input and output; tool call and tool response apply to agents only. Images attached to a prompt are part of the user input, so a control at user input stops them before the model processes them; the call fails with an HTTP 400 error carrying the content_filter code, which the app can catch. A control at output filters what the model returns — for an image model, the generated image.

Blocking levels

Each control has a blocking level, and the names read backwards from what many people expect: the level names how sensitive the filter is, not which severity it blocks.

Blocking levelBlocksAllows
LowHigh severity onlySafe, low, medium
MediumMedium and highSafe, low
HighLow, medium and highSafe

Content classified as safe is never blocked and isn't configurable. So "block anything above safe" means the High blocking level, applied at every point that must be covered — for a generation app, both user input (the prompt) and output (the image). To loosen filtering for legitimate use, such as nudity in classical art, move the control toward Low, which still blocks high-severity content.

Turning a control off

Turning a content-harm control off completely is allowed on inputs for all customers. Turning it off on outputs for models sold directly by Azure requires approval through the Limited Access Review for modified guardrails.

How do you detect prompt injection hidden in image text?

You detect indirect prompt injection carried in an image by extracting the image's text first (for example with OCR or Azure Content Understanding) and sending that text to Prompt Shields as a document. Prompt Shields analyses supplied text; it is not documented to read pixels, so the extraction step is what makes image-borne instructions visible to it.

Prompt Shields distinguishes two attack types by where the text comes from:

FieldAttack typeWhat goes in itResult
userPromptUser prompt attack (jailbreak)What the user typeduserPromptAnalysis.attackDetected
documents (array)Document attack (indirect injection)Third-party content the model will read: files, emails, web pages — and text extracted from uploaded imagesdocumentsAnalysis[i].attackDetected, one per document, in the order sent

Text from a receipt photo or screenshot is third-party content, so it belongs in documents. The REST call is POST {endpoint}/contentsafety/text:shieldPrompt?api-version=2024-09-01:

pages = [ocr_text_page1, ocr_text_page2]
payload = {"userPrompt": user_message, "documents": pages}
resp = requests.post(shield_url, headers=auth_headers, json=payload)
verdicts = resp.json()

flagged = [
    page for page, doc in zip(pages, verdicts["documentsAnalysis"])
    if doc["attackDetected"]
]
prompt_attack = verdicts["userPromptAnalysis"]["attackDetected"]

Here shield_url is the text:shieldPrompt URL above. Because results come back in the order the documents were sent, zipping the two lists tells you exactly which page carried the attack.

The response holds Booleans, not severities — severities and categoriesAnalysis belong to the harm APIs. Harm APIs are also the wrong check for injection: a quiet "approve this claim" instruction contains nothing hateful or violent.

Request limits

One Prompt Shields request accepts a user prompt of up to 10,000 characters and up to five documents with a combined 10,000 characters. Multi-page scans must be batched so that every request satisfies both limits at once — the document count and the combined character total — so whichever limit a batch reaches first decides its size. For example, short pages of about 1,500 characters fit five to a request (the count limit binds first), while longer pages hit the character limit before the count. The whole upload counts as attacked if any document returns attackDetected.

Why don't document attack detection and Spotlighting catch text in an image part?

They don't catch it because both act on delimited document text, and a photo sent only as an image_url content part isn't document text. In a guardrail, document attack detection for model calls inspects document content at the user input point, and Microsoft notes that detecting indirect attacks requires the prompt to mark documents with document delimiters. Spotlighting — a Prompt Shields option that transforms document content (by base64-encoding it) so the model treats it as data rather than instructions — likewise works on that document content, and it is available for Chat Completions, not for agents.

So a Chat Completions app that sends a contract photo purely as an image part gets no injection protection from either control, however high it sets them. The fix is to extract the photo's text and send it as a delimited document, which brings it under both document attack detection and Spotlighting. Raising the vision detail setting doesn't help and can make the printed text easier for the model to read.

How do you design an app to limit the impact of image-borne injection?

You limit the impact of image-borne injection with defence in depth: assume some injected text will get past detection, and design so that it can't achieve much. The controls that work:

  • A tool-less extraction step. Have a step with no tools convert each image into fixed schema fields (booking reference, amount, date). The agent that holds tools then receives typed data instead of the image's free text, so there is nowhere for an instruction to hide.
  • Human approval for consequential tools. Require a person to approve actions such as changing reservations or approving payments, so a manipulated plan is stopped before it takes effect.
  • Detection before the agent runs. Check extracted text with Prompt Shields as a document (previous sections).
  • Least privilege for tools. Give the agent only the tools and scopes the task needs.

Generation and sampling settings shape how a model phrases its output, not whose instructions it follows, so tuning them is not an injection defence. The effective controls change what the model sees or what its actions can do.

The app decides what to do with a detection

Prompt Shields returns verdicts; it doesn't block or route anything. Your application chooses the response, and it should be proportionate to where the attack was found. If documentsAnalysis flags the screenshot text but userPromptAnalysis is clean, withhold that document from the model (and flag it for review) while still answering the user's legitimate question. The general principles: scope the response to the content that was flagged rather than to the whole conversation, and never rely on telling the model to ignore content you have already identified as an attack — if flagged text still reaches the model, the attack still has its chance. A document verdict carries as much weight as a user-prompt verdict.

How do you apply watermarks and provenance to generated images?

You meet a visible-labelling requirement by having the application composite a visible label or watermark into the image's pixels after generation and before publishing. Two principles decide this: a requirement that must hold every time belongs in deterministic code rather than in a generation instruction, and a label people must see has to be in the pixels — anything stored beside the image (storage metadata, tags, database fields) travels separately and is invisible to a viewer.

Separately, Azure OpenAI attaches Content Credentials to every image generated by the DALL-E and GPT-image-1 series models. Know how they differ from a visible watermark:

Visible watermarkContent Credentials
Who adds itYour applicationThe service, automatically — no deployment or guardrail setting
Where it livesIn the pixelsA C2PA manifest attached to the image file
What it recordsWhatever text or logo you drawDescription "AI Generated Image", the softwareAgent and a timestamp
TrustNone beyond the image itselfCryptographically signed by a certificate that traces back to Azure OpenAI
How people see itDirectlyWith a verification tool, such as the Content Credentials Verify site or the Content Authenticity Initiative open-source tools

A provenance policy often uses both: Content Credentials for machine-verifiable origin, and a visible label where regulations or brand policy require anyone to see it. Note that editing or re-encoding an image can strip its metadata, so publishing pipelines should preserve the manifest where it matters.

How do you flag prohibited symbols and enforce brand rules?

You flag known harmful symbols with the built-in classifiers, flag organisation-specific or newly emerging symbols with custom categories (rapid) image incidents, and check brand usage with Azure Content Understanding classify fields — then combine those signals with deterministic rules in code.

Built-in categories vs custom incidents

Widely known hate symbols (such as glorified Nazi imagery) fall within the Hate category's image definitions, so Analyze Image with your own threshold handles them. A brand-new emblem or a local gang logo is not something the built-in classifier learned, and lowering the Hate threshold won't teach it. For that, the custom categories (rapid) API is designed for emerging incidents, with no training step:

  1. Create an image incident (PATCH /contentsafety/image/incidents/{name}).
  2. Add example images with :addIncidentSamples (up to 1,000 per incident).
  3. Deploy it with :deploy — an incident isn't available for analysis until it is deployed.
  4. Call image:detectIncidents with the incident names to check new images against the samples.
ToolWorks on images?Notes
Custom categories (rapid)Yes (text and image incidents)No training step; up to 1,000 samples per incident; ready after deploy
Custom categories (standard)No — text onlyTrained model, needed at least 50 positive samples; retired on 1 September 2026
BlocklistsNo — text onlyExact term matching; listing a symbol's name doesn't match its picture

Brand usage with Content Understanding

Brand checks ask fixed questions about every image — is the logo visible, is it the approved version, is a competitor's sign in view. Build a Content Understanding analyzer whose baseAnalyzerId is prebuilt-image and define one field per question using the classify method, which picks a value from a fixed enum (Yes/No, Approved/Outdated/Missing). Every image returns the same shape, which a rules engine can act on directly. The principle: when downstream code acts on the answer, prefer a field whose possible values are fixed in advance over one whose output is open-ended.

Decide in code

When a policy combines several rules and auditors need consistent, explainable outcomes, gather one signal per rule — a Content Understanding field, a rapid incident match, an Analyze Image severity (for example, Sexual no higher than low, which is 2) — and make the final decision in deterministic code. The same signals then always give the same decision, and each rejection names the rule that failed. Keep models and classifiers as signal producers and keep the policy decision itself in code you can test and audit; guardrails, for their part, cover harm categories rather than brand rules.

Tip. Expect short scenarios in which a company moderates uploads or generated images under a constraint — no model in the flow, no moderation code, no keys or SAS tokens, within a day without training, one request, least custom code, or the same decision for the same signals. You choose the right service (Analyze Image, the image-with-text API, a guardrail, Prompt Shields, a rapid image incident, a Content Understanding analyzer), the right setting (blocking level, intervention point, enableOcr, role assignment), or interpret results such as image severities and documentsAnalysis. Short Python items ask you to complete an SDK or REST call, and some items combine two facts, such as the trimmed image scale with an app threshold, or the per-request limits with a batching decision.

Key takeaways
  • Analyze Image scores Hate, Sexual, Violence and Self-harm; the app compares each severity with its own threshold — the API never blocks.
  • Image severities use only 0, 2, 4 and 6 (safe, low, medium, high); write image thresholds against those values.
  • Images must be at most 4 MB and 50 x 50 to 7,200 x 7,200 pixels; animated images are judged by their first frame only.
  • With a blobUrl, the Content Safety resource's system-assigned identity reads the blob and needs Storage Blob Data Contributor or Owner.
  • The image-with-text API with enableOcr judges an image and its text together, but only up to 1,000 characters; score longer text with Analyze Text.
  • Guardrail blocking levels: Low blocks high only, Medium blocks medium and high, High blocks everything above safe; safe content is never blocked.
  • Turning a harm control off on outputs needs modified-guardrail approval; on inputs it doesn't.
  • Prompt Shields reads text, not pixels: extract image text and send it in the documents array, then act on documentsAnalysis[].attackDetected.
  • Content Credentials are an automatic, signed C2PA manifest seen only with verification tools; a visible label must be composited by the app.
  • New or organisation-specific symbols need a deployed custom categories (rapid) image incident; blocklists and standard custom categories are text-only.

Frequently asked questions

What severity values does Azure AI Content Safety return for images?

The Azure AI Content Safety image model returns a trimmed severity scale of 0, 2, 4 and 6, meaning safe, low, medium and high, for each of the Hate, Sexual, Violence and Self-harm categories. Values such as 3 or 5 don't occur for images, so application thresholds should be written against 2, 4 and 6.

Does Content Safety analyze every frame of an animated GIF?

No. For animated image formats, the Analyze Image API extracts and analyzes only the first frame. To moderate a whole animation, the application must split it into frames and send each frame, or a dense enough sample, as a separate image and combine the results.

Which role does Content Safety need to read images from Blob Storage?

When an image is passed as a blobUrl, the Content Safety service reads it itself, so enable the Content Safety resource's system-assigned managed identity and assign it Storage Blob Data Contributor or Storage Blob Data Owner on the storage account. Microsoft documents these as the only valid roles; no SAS token or account key is needed.

How do I catch harmful captions on otherwise harmless images?

Use the Content Safety multimodal image-with-text API with enableOcr set to true. It runs OCR on the image and analyzes the recognised text together with the visual content in one request. It reads at most 1,000 characters of text, so very text-heavy images should also have their full text scored with the Analyze Text API.

What do the Low, Medium and High blocking levels mean in Foundry guardrails?

In Microsoft Foundry guardrails, the blocking level sets how sensitive a content-harm control is. Low blocks only high-severity content, Medium blocks medium and high, and High blocks low, medium and high severity. Content classified as safe is never blocked at any level.

Can Prompt Shields detect instructions hidden inside an image?

Prompt Shields analyzes text, so an application must first extract the image's text, for example with OCR, and send it in the documents array of a Prompt Shields request. Each document returns its own attackDetected result. One request takes up to five documents with a combined 10,000 characters.

Is the Content Credentials manifest a visible watermark?

No. Content Credentials are a cryptographically signed C2PA manifest that Azure OpenAI attaches automatically to images from the DALL-E and GPT-image-1 series models, recording that the image is AI generated. People see it only with a verification tool. A label any viewer can see must be composited into the image pixels by the application.

How do I flag a newly emerging prohibited symbol in images?

Create a Content Safety custom categories (rapid) image incident, add example images as samples, deploy the incident, and call image:detectIncidents on new images. It needs no training, so it can be live within hours. Text blocklists and the retired standard custom categories API work on text only.

Source

This lesson covers the "Implement computer vision solutions" domain of the official AI-103 exam guide. Vendors revise their guides — check the source for the current version.

Test yourself on this topic
Practice now

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.

Spotted a mistake in this lesson?