Resolved

The read-only check was a regex match

Copilot in SQL Server Management Studio enforced its read-only mode with a regex blocklist. A statement built so the checker saw one thing while the database ran another walked straight past it, and instructions planted in the database's own metadata could point it at a sysadmin session. Microsoft fixed the flaw in SSMS 22.8.2.

Logged 11 Oct 2026

The read-only gate was a list of forbidden words

SQL Server Management Studio added a Copilot assistant that could run queries against the connected database. To keep it from doing anything destructive, the extension shipped a read-only mode, and per Johann Rehberger's research that mode was enforced by a regex blocklist inside a class named LocalSqlExecutionAccessChecker. The check scanned a statement for patterns it considered dangerous and allowed everything it did not recognize. A statement can be built so that the text the checker sees does not contain the forbidden tokens while the database still executes the hidden command.

The bypass Rehberger demonstrated carried the statement name in a variable. A declaration set a sysname variable to the string sp_executesql, and the EXEC named the variable rather than the procedure. The checker saw an execution of a variable, the blocklist never matched, and the database ran the inner statement with the connected user's privileges. A second path ran through RestoreVerifyBackupFile. Because Copilot ran with the rights of whoever was connected, a user holding db_owner who could reach a sysadmin session could escalate to sysadmin.

Instructions planted in the database's own description of itself

The other half of the finding was how instructions reach the assistant at all. Rehberger showed that database metadata is a writable channel: extended properties set via sp_addextendedproperty, AGENTS.md per object and CONSTITUTION.md database-wide, which Copilot automatically discovers and folds into its prompt context, and which can be written at a lower privilege than the one that later runs the assistant. A db_owner can plant text there. When a sysadmin session later asks Copilot about that object, the assistant reads the planted text as context and acts on it, which makes the database's own description of itself an indirect prompt injection vector.

The two halves compose. The planted instruction tells the assistant what to run, the regex bypass lets the run escape the read-only intent, and the privileges of whoever is sitting in the session decide how far it reaches. Rehberger presented the work at BlueHat Asia on 17 and 18 September 2026.

The fix, and why the shape keeps returning

Microsoft assigned CVE-2026-65669, scored 9.6, and fixed the flaw in SSMS 22.8.2, with earlier 22 releases affected. It separately ships administrative controls for SQL Copilot: disabling Copilot, configuring group policies, and setting an execution context. The advisory credits the find.

A safety property enforced by matching text is only as strong as the match, and here the text being matched is under the caller's control. The checker and the database disagreed about what was about to run, and the database was the one that got to decide. Read-only was a regex, and the regex could be read past.

Sources

Research

Thread

  • Relates to: Codex read its way out of read-only

    Both are read-only modes an agent talked its way out of; there the escape was reading the very files the restriction guarded, here it was a statement the checker could not see the inside of.

  • Related to: Refused in the reply, dispatched by the framework

    Both turn on an authorization check that either answers the wrong question or, here, is simply absent before dispatch. There the check ran and verified the wrong thing; in the repeat-after-me transcript no pre-execution check stood between the model's output and the orchestrator's call at all.

  • Relates to: The guard read bash and stopped looking

    The same failure of a text-shaped guard: a blocklist that matches on what it is shown rather than on what will run.

  • Related to: Twenty-five agent CVEs in two days, from one researcher

    Both are authorization checks that run, pass, and answer a question adjacent to the one that mattered. 1MCP checks which tags a filter names rather than which backends it selects; Argo CD MCP checks nothing about where the final normalized path lands.

  • Related to: Above 256 kilobytes, the preview pane read the disk

    Both are controls that covered one path and not another. There a check only blocked the shapes it matched; here the strict policy applied to small files and the file: URL path received none of it.

  • Related to: RestrictedPython was never a dependency

    Both are controls that existed as a description rather than an enforcement. SSMS Copilot matched a regex where it meant to check a mode; Astron Agent’s executor advertised a sandbox in a docstring while shipping the unsandboxed default.