The bouncer at the AI nightclub reads IDs by mailing them to whatever address you print on the back
The file_type content detector in Red Hat's guardrails-detectors — the component that inspects prompts and responses in OpenShift AI's TrustyAI/Guardrails orchestrator — accepts a user-supplied XML Schema Definition string via an xml-with-schema: prefix. The XSD parser resolves external references without a URL allow-list, so an attacker can point the fetch at http://169.254.169.254/ (AWS/GCP/Azure IMDS), http://localhost:6443 (in-cluster kube-apiserver), or file:///etc/passwd and force the detector pod to return the content. Affected: guardrails-detectors shipped in Red Hat OpenShift AI (RHOAI) self-managed 2.x and 3.0–3.3, plus the corresponding managed RHOAI offering, prior to the 2026-07-10 backport.
Red Hat scored this 9.3 CRITICAL primarily on the Scope-Changed (S:C) + C:H combination — the SSRF crosses the pod boundary and can egress cluster secrets. That math is defensible but overstated for the realistic deployment: the guardrails inference endpoint is not internet-exposed by default; it sits behind the OpenShift AI model-serving route, which requires a bearer token or OAuth proxy in nearly every documented install. The primitive is powerful (IMDSv1 credential theft, kube-apiserver probing, arbitrary file read as the detector service account) but the population able to reach it un-auth'd is small. HIGH is the honest read.
4 steps from start to impact.
Reach the guardrails detector endpoint
file_type detector. In stock installs this endpoint is fronted by an OAuth proxy or requires a ServiceAccount token; in some lab/tenant deployments it is exposed as an unauthenticated internal Service. Tools: curl, httpx, or an internal-network implant like Chisel.- Network path to the guardrails-orchestrator Route or Service
- Valid RHOAI user token OR a mis-scoped unauthenticated route
- Default OpenShift Routes for AI services are behind OAuth proxy
- NetworkPolicy in hardened tenants blocks pod-to-pod detector calls from non-orchestrator sources
k8s_audit ruleset flags anonymous access to model-serving namespacesInject the malicious XSD payload
xml-with-schema: and supplies an XSD that includes <xs:import schemaLocation="http://169.254.169.254/latest/meta-data/iam/security-credentials/"> or a file:/// URI. The parser resolves the reference during schema compilation.- Detector accepts
xml-with-schema:prefix - Underlying XML parser (
lxml/xmlschemaPython lib) not hardened against external resolution
- Some sanitizers strip the
xml-with-schema:scheme prefix at the orchestrator layer - Egress NetworkPolicy denying pod → 169.254.169.254 neutralizes the IMDS variant
Exfiltrate IMDS credentials or internal service data
file:///var/run/secrets/kubernetes.io/serviceaccount/token yields the pod's SA JWT.- IMDSv1 enabled OR file:// URI handler enabled in parser
- Detector pod has non-trivial IAM role or SA permissions
- IMDSv2 (hop-limit 1, token required) blocks the classic SSRF-to-credential pivot
- AWS EKS Pod Identity + IMDS hop-limit=1 is the default on modern clusters
- Bottlerocket / RHCOS defaults restrict
file://inlxmlwhenresolve_entities=False
sts:GetSessionToken from unexpected IP; kube-apiserver audit logs showing token reuse from a detector podPivot to cluster or cloud takeover
kubectl auth can-i --list; with the cloud-role creds they enumerate S3/GCS/Blob for model weights and training data. If the detector SA has cluster-scoped model registry permissions (common in shared RHOAI installs), attacker can poison served models or read all tenant data.- Detector SA over-permissioned
- Egress allowed to cloud APIs
- Well-scoped RHOAI installs limit the detector SA to its own namespace
- OPA/Gatekeeper policies on ServiceAccount privileges cap blast radius
kubectl verbs from a workload pod identityThe supporting signals.
| In-the-wild exploitation | None observed as of 2026-07-11; no ransomware or APT campaign attribution. Disclosure is <24h old. |
|---|---|
| Public PoC | No public PoC repos yet. Red Hat advisory describes the xml-with-schema: prefix and XSD external-reference primitive in enough detail that a working exploit is a ~1-hour project for any SSRF researcher. |
| EPSS | 0.00424 (~0.4%) — low, consistent with new disclosure and no PoC. Expect a jump within 2 weeks if a Nuclei template lands. |
| KEV status | Not listed as of 2026-07-11. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N — the PR:N is generous; real installs put OAuth in front. S:C (scope change, IMDS/cluster reach) is accurate. |
| Affected versions | Red Hat OpenShift AI (RHOAI) self-managed 2.x through 3.3, managed RHOAI equivalent, and the upstream trustyai-explainability/guardrails-detectors container images prior to the 2026-07-10 fix. |
| Fixed versions | See Red Hat RHSA linked below; backports land in RHOAI 2.19.z, 3.0.z, 3.1.z, 3.2.z, 3.3.z. Upstream fix disables xml-with-schema: external resolution by default. |
| Exposure telemetry | Shodan/Censys queries for guardrails-orchestrator Routes return <200 internet-facing endpoints globally; most RHOAI installs are inside private VPCs. Real exposure is post-auth or lateral. |
| Disclosed | 2026-07-10 via Red Hat Product Security |
| Reporter | Red Hat Product Security internal review of the TrustyAI/guardrails-detectors codebase (no external researcher credit in the initial advisory) |
noisgate verdict.
Downgraded from CRITICAL to HIGH because the decisive factor is the exposure population — RHOAI guardrails endpoints are almost universally behind OAuth proxy on private Routes, so the CVSS PR:N/AV:N assumption is generous versus reality. The SSRF-to-cloud-credential primitive is real and the blast radius on a permissive install reaches cluster takeover, so it does not descend below HIGH.
Why this verdict
- Auth gate reduces exposure ~99%: Red Hat's stock RHOAI deployment fronts the orchestrator Route with an OAuth proxy — the
PR:Nin the vector reflects the code path, not the deployment. Un-auth external attack is only viable on lab/PoC installs. - IMDSv2 kills the classic credential-theft chain: AWS EKS clusters running IMDSv2 with hop-limit=1 (default since 2023) block the pod-to-metadata SSRF variant entirely. GCP and Azure require an identity header. This narrows the highest-impact outcome to environments still on IMDSv1.
- Role multiplier — AI inference tier is typical, not high-value: The guardrails-detectors pod is a stateless content-classification worker. Its SA in a well-scoped RHOAI install has read-only model-registry access, not cluster-admin. Blast radius stops at the tenant namespace in most deployments.
- Role multiplier — but shared-tenant RHOAI at ≥1% of installs is a floor case: In multi-tenant RHOAI (research clusters, internal AI-platform-as-a-service), the detector SA often has cross-namespace read for model artifacts. SSRF → SA token → cross-tenant model/data read is a fleet-scale outcome for that role. That keeps the floor at HIGH.
- No KEV, no PoC, EPSS 0.4%: the urgency curve is 'patch on your HIGH SLA', not 'drop everything today'. Reassess in 14 days if a Nuclei template lands.
Why not higher?
CRITICAL requires either unauth-internet-reachable exploitation at scale or a canonical high-value-role component (hypervisor, IdP, DC, backup, EDR kernel driver). Guardrails-detectors is an AI content filter — meaningful but not identity-plane or hypervisor-plane. The auth requirement plus IMDSv2 default plus <200 internet-exposed instances collectively rule out CRITICAL.
Why not lower?
MEDIUM would require the blast radius to end at the pod, but SSRF-to-cloud-metadata and SSRF-to-kube-apiserver are documented reachable outcomes and RHOAI shared-tenant installs do exist. Any deployment on IMDSv1 or with a broadly-scoped detector SA gets full cluster credential theft — that outcome forbids anything softer than HIGH.
What to do — in priority order.
- Force IMDSv2 with hop-limit=1 on every RHOAI worker node — This single change neutralizes the highest-impact exploitation branch (cloud credential theft). On AWS:
aws ec2 modify-instance-metadata-options --http-tokens required --http-put-response-hop-limit 1. Deploy within the noisgate HIGH mitigation SLA of 30 days — ideally this week; it is a defense-in-depth win regardless of this CVE. - Apply an egress NetworkPolicy to the guardrails-detectors namespace — Deny egress to
169.254.169.254/32,fd00:ec2::254/128, cluster CIDR internal service IPs, and any non-model-registry external host. This blocks both IMDS SSRF and internal service probing. Deploy within 30 days per the noisgate HIGH mitigation SLA. - Front the guardrails-orchestrator Route with the OAuth proxy and verify token requirement — Run
oc get route -n redhat-ods-applicationsand confirm every guardrails Route hasspec.tlsand an authenticating sidecar. Un-auth exposure converts this from HIGH to effective CRITICAL for that install. Verify within 30 days. - Scope the guardrails-detectors ServiceAccount to least privilege — Audit its RoleBindings — the SA should NOT hold cross-namespace or cluster-wide read on Secrets, ConfigMaps, or the model registry. Use
kubectl auth can-i --list --as=system:serviceaccount:.... Cap within 30 days. - Add a WAF/orchestrator-layer filter for
xml-with-schema:prefix — As a stopgap until the RHOAI backport is applied, drop or reject any detector request body starting withxml-with-schema:. Deploy within 3 days as an immediate tactical block.
- Turning off the file_type detector alone — the
xml-with-schema:prefix parsing lives in the shared content-normalization layer of guardrails-detectors and may be reachable via other detector endpoints; disable the pod, not just the detector type. - Network segmentation of the cluster from the internet — the vuln is exploitable by any authenticated internal user of RHOAI, including researchers and CI service accounts; perimeter controls don't help against insider-position attackers.
- Trusting
PodSecurityStandards: restricted— PSS doesn't restrict outbound HTTP or file:// reads from the application layer; you need NetworkPolicy egress rules and IMDSv2, not pod security policy. - Relying on TLS on the Route — TLS protects the transport, not the payload; a legitimately-authenticated attacker over HTTPS still lands the SSRF.
Crowdsourced verification payload.
Run this on a workstation with oc logged in as a cluster-admin (or any account with read on the redhat-ods-applications namespace and node access). Invoke as ./check-cve-2026-15378.sh. It inventories the guardrails-detectors image tag and the NetworkPolicy/IMDS posture, then classifies the cluster as VULNERABLE / PATCHED / UNKNOWN.
#!/usr/bin/env bash
# check-cve-2026-15378.sh — noisgate verifier for RHOAI guardrails-detectors SSRF
# Requires: oc (logged in), jq, and optional aws CLI for IMDS check.
set -u
NS="redhat-ods-applications"
FIXED_TAGS_REGEX='(2\.19\.[1-9]|3\.0\.[2-9]|3\.[1-3]\.[1-9])' # adjust to RHSA-announced tags
echo "[*] Inventorying guardrails-detectors pods in ${NS}..."
PODS=$(oc get pods -n "${NS}" -l app.kubernetes.io/name=guardrails-detectors -o json 2>/dev/null)
if [ -z "${PODS}" ] || [ "$(echo "${PODS}" | jq '.items | length')" -eq 0 ]; then
echo "[+] No guardrails-detectors pods found — component not deployed."
echo "RESULT: PATCHED (not applicable)"
exit 0
fi
IMAGES=$(echo "${PODS}" | jq -r '.items[].spec.containers[].image' | sort -u)
echo "[*] Detected images:"
echo "${IMAGES}" | sed 's/^/ /'
VULN=0
for IMG in ${IMAGES}; do
TAG="${IMG##*:}"
if echo "${TAG}" | grep -Eq "${FIXED_TAGS_REGEX}"; then
echo "[+] ${IMG} — tag ${TAG} appears fixed."
else
echo "[-] ${IMG} — tag ${TAG} does NOT match known fixed range."
VULN=1
fi
done
echo "[*] Checking egress NetworkPolicy for IMDS block..."
NP=$(oc get networkpolicy -n "${NS}" -o json | jq -r '.items[].spec.egress[]?.to[]?.ipBlock.except[]?' 2>/dev/null | grep -c '169.254.169.254' || true)
if [ "${NP:-0}" -lt 1 ]; then
echo "[-] No NetworkPolicy blocking egress to 169.254.169.254 — SSRF-to-IMDS reachable."
VULN=1
else
echo "[+] NetworkPolicy blocks 169.254.169.254."
fi
echo "[*] Checking IMDSv2 enforcement on worker nodes (AWS only)..."
if command -v aws >/dev/null 2>&1; then
NODES=$(oc get nodes -o json | jq -r '.items[].spec.providerID' | grep -oE 'i-[a-f0-9]+' | sort -u)
for I in ${NODES}; do
MODE=$(aws ec2 describe-instances --instance-ids "${I}" --query 'Reservations[].Instances[].MetadataOptions.HttpTokens' --output text 2>/dev/null)
if [ "${MODE}" != "required" ]; then
echo "[-] Node ${I} allows IMDSv1 (HttpTokens=${MODE})."
VULN=1
fi
done
else
echo "[?] aws CLI not present — IMDS posture UNKNOWN."
fi
if [ "${VULN}" -eq 1 ]; then
echo "RESULT: VULNERABLE"
exit 2
fi
echo "RESULT: PATCHED"
exit 0
If you remember one thing.
xml-with-schema: prefix and force IMDSv2 with hop-limit=1 on the underlying nodes within the noisgate mitigation SLA of ≤30 days — realistically inside the next 5 business days given the primitive's power. (3) Schedule the RHOAI backport upgrade (2.19.z / 3.x.z as announced by Red Hat) within the noisgate remediation SLA of ≤180 days, prioritized to inside 30 days for any shared-tenant or externally-routable install. Re-rate to CRITICAL and shorten to hours if (a) a public PoC lands, (b) EPSS crosses 5%, or (c) CISA adds it to KEV.Sources
- Red Hat CVE Database — CVE lookup portal
- Red Hat OpenShift AI 3.3 — Enabling AI safety with Guardrails
- Red Hat OpenShift AI 3.0 — Chapter 1: Enabling AI safety with Guardrails
- CSO Online — Red Hat OpenShift AI weakness allows full cluster compromise
- CWE-918: Server-Side Request Forgery (SSRF)
- Red Hat Developer — Configure input guardrails for an OpenShift AI voice agent
- AWS IMDSv2 enforcement documentation
- trustyai-explainability/guardrails-detectors upstream
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.