SW-CFG-013: Database or cluster MCP server with write access although a read-only mode exists
Last updated 7 November 2026
| Fact | Value |
|---|---|
| Severity | High |
| Checks | Configuration file |
| Malicious indicator | No |
| OWASP Agentic Top 10 | ASI03 |
| OWASP MCP Top 10 | MCP02 |
| NIST SP 800-53 | AC-3, AC-6 (provisional mapping to SP 800-53 base controls) |
| First shipped in | Scanner 1.8.0 |
What it detects
The rule reads the servers of the MCP client files and the inline servers of a plugin manifest against a short list of servers that can write and the switch that restricts each. The hosted Supabase endpoint mcp.supabase.com, in the server's url or in a launcher argument, fires without read_only=true in its query. The package @supabase/mcp-server-supabase, run directly or through npx, bunx or pnpm dlx, fires without --read-only. A Kubernetes server (kubernetes-mcp-server or mcp-server-kubernetes) fires with neither --read-only nor --disable-destructive, and without ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS=true in its environment.
Any other server fires when its environment sets a key ending in ACCESS_MODE to unrestricted, passes --access-mode unrestricted, or sets an insert, update, delete or DDL enable flag (for example ALLOW_INSERT_OPERATION) to true. A --read-only argument, a read_only or readOnly key in the server object, an entry with disabled: true or enabled: false, and a Supabase server whose features name only docs are all quiet. So is any file under a folder named test, tests, fixtures, testdata or a similar name, because no client loads it. A server yields one finding on its own line, and the evidence names the missing switch.
Why it matters
These servers let the agent change a database or a cluster, and the same servers offer a mode that only reads. Without it, a mistaken tool call or an instruction hidden in data the agent reads can delete rows, alter a schema or remove cluster resources, and the damage is limited only by what the connection's credentials may do. The scanner maps this rule to OWASP MCP02, Privilege Escalation via Scope Creep, and ASI03, Identity and Privilege Abuse, and to NIST SP 800-53 controls AC-3, Access Enforcement, and AC-6, Least Privilege.
Example
The server below uses the hosted endpoint of a database provider, and its query does not contain read_only=true:
.mcp.json
{
"mcpServers": {
"database": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?project_ref=EXAMPLE0000"
}
}
}The evidence reads database: hosted endpoint without read_only=true.
How to fix
Add the switch the server offers: read_only=true to the hosted address, --read-only to the package, and --read-only or --disable-destructive to a Kubernetes server.
When writing is really needed, give it to a separate entry with a narrow scope and keep that entry disabled until the work starts, so that day-to-day sessions only read.
If it is a false positive
A server in a project whose job is to change its database, such as a migration helper, is reported although writing is the point. Accept the finding with a note that says which environment the server points at and why it writes, and keep the expiry short.
If the finding is not a problem in your case, accept it with a note: in the dashboard a manager or owner can accept a finding and the note is kept with it; with the scanner on its own, add it to the baseline file with a reason and an expiry date.