It is like a bank vault where any teller with a desk key can walk through the safety-deposit wall
CVE-2026-91503 is a flaw in the Virtual Private Database (VPD) component of Oracle Database Server, affecting versions 19.3–19.32, 21.3–21.23, and 23.4.0–23.26.3. A database user who holds the CREATE TABLE privilege — a common grant for application service accounts, ETL users, and developers — can manipulate how VPD security-policy contexts are evaluated during data operations over Oracle Net. The result: the attacker bypasses row-level and column-level VPD predicates entirely, gaining read *and* write access to every row the VPD was supposed to hide. Confidentiality and integrity are both rated HIGH; availability is unaffected.
Oracle rates this HIGH at CVSS 8.1, and that is *broadly fair but slightly generous*. The 8.1 score already accounts for the PR:L authentication requirement, but it does not discount two important real-world factors: (1) VPD is an *optional* feature — only databases that actively use it are affected, and (2) Oracle Database listeners on port 1521 are almost never internet-exposed in well-run enterprises, which means the attacker typically needs internal network positioning or compromised application credentials first. On the other hand, VPD exists specifically to guard the *most sensitive* data (PII, financial records, healthcare data), so when the bypass lands, the blast radius is the worst data in the house. We downgrade marginally to 7.5 while keeping the verdict at HIGH.
4 steps from start to impact.
Obtain authenticated Oracle Net session
PR:L — no DBA or SYSDBA role is needed, just a standard session.- Valid database credentials for the target instance
- Network route to Oracle TNS listener (port 1521/1522)
- Oracle TNS listeners are rarely exposed to the internet; Shodan historically shows <20,000 globally, most in cloud dev environments, not production
- Credential theft requires a prior compromise stage (phishing, config leak, lateral movement)
Confirm CREATE TABLE privilege
CREATE TABLE system privilege (or CREATE ANY TABLE). This privilege is commonly granted to application schemas, ETL service accounts, and development users. It is *not* a default grant for read-only reporting accounts, which limits the vulnerable population to a subset of database users.- Database account holds CREATE TABLE or CREATE ANY TABLE privilege
- Read-only and reporting accounts typically lack this grant
- Principle-of-least-privilege shops revoke DDL from production service accounts
CREATE TABLE system privilege usageCraft DDL-based VPD policy bypass
CREATE TABLE ... AS SELECT that copies data from VPD-protected tables, or manipulating policy group arguments during DDL execution. The VPD predicate that should filter rows is not applied to the DDL path, so the attacker's new table contains every row.- Target table must be protected by a VPD policy
- Attacker can issue DDL statements against the schema
- Database Vault realms can block DDL in protected schemas even if the privilege exists
- SQL firewall / Database Activity Monitoring (DAM) tools flag anomalous DDL patterns
CREATE TABLE ... AS SELECT on VPD-protected schemas; Imperva/Guardium DAM rules for bulk copy operationsExfiltrate or modify protected data
C:H and I:H, meaning the attacker can also issue UPDATE/DELETE/INSERT against protected data. In regulated environments (healthcare, finance), this is a reportable breach of the most sensitive records — exactly the data VPD was deployed to protect.- Successful VPD policy bypass from step 3
- Data Loss Prevention (DLP) tools may flag large result-set exports
- Oracle Database Vault and privilege analysis can detect anomalous data access volumes
CREATE TABLE. This directly breaks the attack chain at step 2. Deploy within 30 days per the noisgate mitigation SLA for HIGH-severity findings. Use SELECT * FROM DBA_SYS_PRIVS WHERE PRIVILEGE LIKE '%CREATE%TABLE%' to enumerate grants.CREATE TABLE ... AS SELECT statements targeting VPD-protected schemas. This does not prevent the exploit but provides near-real-time detection, enabling rapid incident response. Deploy within 30 days.- Oracle Advanced Security (TDE/network encryption) — Transparent Data Encryption and network encryption protect data at rest and in transit, but do nothing to prevent an authenticated user from bypassing VPD policies at the SQL layer. The attacker's session is already authenticated and encrypted.
- Oracle Label Security (OLS) alone — While OLS provides an additional access-control layer, it is a separate feature from VPD. Unless OLS policies are independently configured on the same tables, it does not compensate for VPD bypass.
- Web Application Firewall (WAF) — WAFs inspect HTTP traffic, not Oracle Net (TNS) protocol traffic. They provide zero coverage for this attack vector.
The supporting signals.
| In-the-Wild Exploitation | No known exploitation. Not listed on CISA KEV as of 2026-10-22. No threat-intel reports of active campaigns targeting this CVE. The October 2026 CPU was released only 2 days ago. |
|---|---|
| Proof-of-Concept Availability | No public PoC found. Checked pocindex.io, GitHub (no repos named CVE-2026-91503), ExploitDB, and Nuclei templates — all negative. However, the related 2024 VPD DDL-bypass technique by DatabaseSecurityNinja provides a conceptual roadmap that lowers the barrier for skilled attackers. |
| EPSS Score | 0.00278 (approximately 72nd percentile). Low probability of exploitation in the next 30 days, consistent with the authentication requirement and Oracle Database's typically non-internet-facing posture. |
| CISA KEV Status | Not listed. No due date set by CISA. |
| CVSS Vector Interpretation | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N — Network-reachable, low complexity, low privilege required, no user interaction, unchanged scope. High confidentiality and integrity impact, no availability impact. The S:U (unchanged scope) means the attacker stays within the VPD-protected database context. |
| Affected Version Ranges | Oracle DB 19.3–19.32 (19c), 21.3–21.23 (21c), 23.4.0–23.26.3 (23ai). All three active long-term-support and innovation release trains are affected. |
| Fixed Versions | October 2026 CPU patches: 19.33 (19c RU), 21.24 (21c RU), 23.27 (23ai RU). Apply via OPatch or Oracle Release Update mechanism. |
| Internet Exposure (Shodan/Censys) | Shodan historically indexes <20,000 Oracle TNS listeners globally on port 1521, and the vast majority are development/test instances. Production Oracle databases are almost universally behind firewalls. This significantly limits unauthenticated remote attack surface, though the CVE requires authentication anyway. |
| Disclosure Date | 2026-10-20 via Oracle Critical Patch Update October 2026. Coordinated disclosure; no prior public knowledge. |
| Reporting Researcher | Not publicly credited. Oracle CPU advisories typically do not name researchers for database-component vulnerabilities. |
Sources.
- Oracle CPU October 2026 Advisory
- Strix.ai CVE-2026-91503 Detail
- Tenable: Oracle October 2026 CPU Analysis
- SecurityWeek: Oracle Patches 1200+ Vulnerabilities
- DatabaseSecurityNinja: Breaking VPD Through DDL Permissions
- Oracle Docs: Using VPD to Control Data Access
- UK Gov: Open Port 1521 Oracle Database Risk
Why this verdict
- Authentication gate is real friction: The attacker needs valid database credentials with
CREATE TABLEprivilege. This is not unauthenticated remote code execution — it presupposes either insider access, compromised application credentials, or a prior breach stage. The CVSSPR:Lalready discounts this, but real-world credential-theft difficulty further narrows the attacker population. - VPD-specific scope limits the affected population: VPD is an optional feature used primarily in regulated, multi-tenant, or row-level-security deployments. Not every Oracle Database instance uses VPD. Enterprises without VPD policies are unaffected regardless of version. This narrows the blast radius compared to a generic Oracle DB RCE.
- Internal-network positioning required in practice: Oracle TNS listeners are almost never internet-exposed in production. The attacker needs internal network access or a tunneled connection, which implies a prior compromise stage or insider threat. This compounds the friction beyond what the CVSS
AV:Nsuggests. - Role multiplier: Oracle Database is canonically a high-value-role component — production database engines host regulated data (PII, PHI, financial records). VPD specifically protects the *most sensitive* subset of that data. If the chain succeeds on a production Oracle instance with VPD, the outcome is mass data egress of the most sensitive records — a reportable breach. This sets a verdict floor of HIGH. The floor holds even with the authentication friction, because (a) application service accounts with
CREATE TABLEare common, and (b) the data at risk is, by VPD's own design, the crown jewels. - No active exploitation or PoC tempers urgency: With EPSS at 0.00278, no KEV listing, no public PoC, and disclosure only 2 days old, the immediate risk of opportunistic exploitation is low. This prevents the verdict from reaching CRITICAL despite the high-value-role floor.
Why not higher?
A CRITICAL rating would require either unauthenticated access, active exploitation, or a scope change enabling lateral movement beyond the database. This CVE demands valid credentials with a specific privilege (CREATE TABLE), has no availability impact, no scope change (S:U), no public PoC, and no observed exploitation. The VPD-specific scope means many Oracle installations are simply unaffected. These factors collectively cap the verdict at HIGH.
Why not lower?
Oracle Database is a canonical high-value component hosting regulated production data. VPD protects the *most sensitive* rows by design — PII, PHI, financial records. Bypassing VPD on a production instance means full access to exactly that data, which constitutes a reportable breach. The CREATE TABLE prerequisite is common among application service accounts, and the exploit complexity is LOW. Dropping below HIGH would understate the blast radius when the chain lands on its intended target.
Crowdsourced verification payload.
Run this script on any host with sqlplus installed and network access to the target Oracle instance. Invoke as: bash check_cve_2026_91503.sh <ORACLE_SID_OR_SERVICE> <HOST> <PORT>. The script connects as a DBA-privileged user (it will prompt for credentials) and checks the database patch level against the fixed Release Update versions. No changes are made to the database.
#!/usr/bin/env bash
# check_cve_2026_91503.sh — Detect CVE-2026-91503 (Oracle VPD policy bypass)
# Usage: bash check_cve_2026_91503.sh <SERVICE_NAME> <HOST> [PORT]
# Requires: sqlplus on PATH, DBA-level credentials (prompted)
# Output: VULNERABLE / PATCHED / UNKNOWN
set -euo pipefail
SERVICE="${1:?Usage: $0 <SERVICE_NAME> <HOST> [PORT]}"
HOST="${2:?Usage: $0 <SERVICE_NAME> <HOST> [PORT]}"
PORT="${3:-1521}"
echo "[*] Checking CVE-2026-91503 on ${HOST}:${PORT}/${SERVICE}"
read -rp "DB Username: " DBUSER
read -rsp "DB Password: " DBPASS
echo
CONN="${DBUSER}/${DBPASS}@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=${HOST})(PORT=${PORT}))(CONNECT_DATA=(SERVICE_NAME=${SERVICE})))"
# Query the current Release Update version
RESULT=$(sqlplus -S "${CONN}" <<'EOSQL'
SET HEADING OFF FEEDBACK OFF PAGESIZE 0 LINESIZE 200 TRIMOUT ON TRIMSPOOL ON
SELECT VERSION_FULL FROM V$INSTANCE;
EXIT;
EOSQL
)
if [ -z "${RESULT}" ] || echo "${RESULT}" | grep -qi "error\|ORA-"; then
echo "[!] UNKNOWN — could not connect or query V\$INSTANCE."
echo " Raw output: ${RESULT}"
exit 2
fi
VERSION=$(echo "${RESULT}" | tr -d '[:space:]')
echo "[*] Detected Oracle version: ${VERSION}"
# Parse major.minor.0.0.RU from VERSION_FULL (e.g., 19.0.0.0.33 or 23.4.0.26.3)
IFS='.' read -ra PARTS <<< "${VERSION}"
MAJOR="${PARTS[0]}"
case "${MAJOR}" in
19)
# 19c: fixed in 19.33 (RU component is PARTS[4])
RU="${PARTS[4]:-0}"
if [ "${RU}" -ge 33 ] 2>/dev/null; then
echo "[+] PATCHED — 19c RU ${RU} >= 19.33"
exit 0
else
echo "[-] VULNERABLE — 19c RU ${RU} < 19.33 (affected range: 19.3-19.32)"
exit 1
fi
;;
21)
# 21c: fixed in 21.24
RU="${PARTS[4]:-0}"
if [ "${RU}" -ge 24 ] 2>/dev/null; then
echo "[+] PATCHED — 21c RU ${RU} >= 21.24"
exit 0
else
echo "[-] VULNERABLE — 21c RU ${RU} < 21.24 (affected range: 21.3-21.23)"
exit 1
fi
;;
23)
# 23ai: fixed in 23.27 — version format is 23.X.0.Y.Z; use PARTS[4]
SUBRU="${PARTS[4]:-0}"
MINORRU="${PARTS[3]:-0}"
# Construct comparable integer: e.g. 23.26.3 -> 2603, 23.27.0 -> 2700
COMP=$(( MINORRU * 100 + SUBRU ))
FIXED=2700 # 23.27.0
if [ "${COMP}" -ge "${FIXED}" ] 2>/dev/null; then
echo "[+] PATCHED — 23ai version ${VERSION} >= 23.27"
exit 0
else
echo "[-] VULNERABLE — 23ai version ${VERSION} < 23.27 (affected range: 23.4.0-23.26.3)"
exit 1
fi
;;
*)
echo "[!] UNKNOWN — major version ${MAJOR} is not in the affected range (19, 21, 23)."
exit 2
;;
esac