oraclemcp is a governed, least-privilege Oracle Database MCP server. It is
read-only by default and escalation-capable up to ADMIN only through an
explicit, confirmation-gated operating-level ladder bounded by each profile's
ceiling. The model is governed, not write-incapable: a fail-closed SQL
classifier refuses anything it cannot prove is permitted at the current
operating level, before the statement reaches Oracle. This document states what
we protect, how to report a vulnerability, and which versions receive fixes.
Security fixes land on the latest released minor line. There is no long-term support branch.
| Version | Supported |
|---|---|
| 0.4.x | ✅ (current line) |
| 0.3.x | |
| < 0.3 | ❌ |
The 0.3.0 → 0.4.0 transition is the production-hardening line; deploy the
latest 0.4.x.
Do not open a public GitHub issue for a security vulnerability.
Report privately through GitHub's coordinated disclosure channel:
- Use Private vulnerability reporting ("Security" tab → "Report a vulnerability") on the repository. This opens a private advisory only the maintainer can see.
Please include:
- the affected version / commit,
- a description of the issue and its impact (which guarantee below it breaks),
- a minimal reproduction (a SQL string, a config, or a request sequence), and
- any suggested remediation.
What to expect:
- Acknowledgement within 7 days.
- An initial severity assessment against the severity policy (P0/P1 are release-blocking).
- Coordinated disclosure: we agree a timeline, ship a fix on the supported line, and credit the reporter unless they prefer to remain anonymous.
This is a single-maintainer project that does not accept outside code contributions (see the README); a focused security report with a clear reproduction is the most useful thing you can send.
The assets are the Oracle database and its data, the connection credentials and signing/auth secrets, and the integrity of the audit chain. The agent driving the server is treated as semi-trusted: it may emit a statement it intends as a read which, through injection or its own error, expresses a write or a privilege escalation. The controls are layered so no single misconfiguration is catastrophic:
- Fail-closed SQL classifier — every statement is classified before it reaches Oracle; anything not provably permitted at the current operating level is treated as dangerous, never the reverse (ADR 0004).
- Governed operating-level ladder —
READ_ONLY < READ_WRITE < DDL < ADMIN, read-only by default, escalation only via a TTL-bounded, confirmation-token step-up capped by each profile'smax_level(no out-of-band device 2FA). - Least-privilege database account — a dedicated read-scoped Oracle user is
the backstop the classifier is paired with (see
docs/operations.md§3). - Signed, hash-chained audit — privileged actions are logged out-of-band to
an append-only, HMAC-SHA256-signed, hash-chained JSONL log, fsynced before
the statement executes, and verifiable with
oraclemcp audit verify(ADR 0003). The log can be shipped to an external WORM store / SIEM for tamper-evidence at an independent destination. - Output fencing + telemetry redaction — row data and logs are fenced and redacted so untrusted database content cannot smuggle instructions back to the agent, and bind values / secrets never reach logs or exporters.
- Driver-adapter seam — all Oracle driver access is isolated behind one seam
(ADR 0002), and every crate is
#![forbid(unsafe_code)].
The full threat model — assets, threats (classifier bypass, privilege
escalation, injection, cancellation-torn commit, audit forgery, secret leak,
prompt-injection via row data), mitigations, and the evidence suites that hold
each mitigation honest — is in docs/threat-model.md.
The deployment-time hardening checklist is in
docs/hardening.md.
Hardening is a shared responsibility. oraclemcp enforces the classifier, the
operating-level ceiling, and the signed audit trail, but it does not manage
the lifecycle of your DB credentials / OAuth secrets / audit key, host an
authorization server, or substitute for database-side controls. A misconfigured
profile ceiling (max_level = "ADMIN") makes confirmation-gated escalation to
ADMIN possible by design — set the ceiling to match the work. See
docs/hardening.md for the controls you own.