TL;DR: SQL Server Management Studio (SSMS) is Microsoft's desktop app for SQL Server. Its built-in AI assistant, GitHub Copilot, runs queries as whoever is connected and follows instructions stored inside the database. Johann Rehberger showed a database owner can write those instructions, so an admin's next Copilot session made the attacker sysadmin, the role that can do anything on the server. SSMS 22.8.2 fixes the read-only bypass he used. The instructions feature stays.
Also this week: a web request that ends with Kubernetes credentials, Claude Code approvals stretched by a lookalike program, a malicious npm release built on a throwaway branch, and a CloudTrail page that shows what we aren't logging.
Attack of the Week: a database owner writes the admin's Copilot prompt
Johann Rehberger at Embrace The Red, "From SELECT to SYSADMIN with SQL Copilot (CVE-2026-65669)" [2026-09-30].
Copilot runs queries on the connection in the open query window. Rehberger: "if the user is connected as sysadmin, then Copilot also executes SQL using that sysadmin connection."
Read-only was a text filter. Copilot's read-only mode blocked queries by matching their text against a list of patterns. Hiding the procedure name in a variable slipped past it:
DECLARE @p sysname='sp_executesql'; EXEC @p N'DROP TABLE [Test];'A second tool, RestoreVerifyBackupFile, ran any T-SQL, SQL Server's query language, as given.
Then he planted the prompt. SSMS stores Copilot instructions as extended properties, free-text labels on a database or table. AGENTS.md goes on a table or column, and CONSTITUTION.md covers the whole database. Copilot loads both on its own, and Microsoft's docs say a db_owner can add them to any object, the database included.
The chain:
A database owner plants a malicious
CONSTITUTION.md.A server admin opens Copilot on that database.
Copilot loads it, and the injected text uses the read-only bypass.
The T-SQL runs on the admin's connection and adds the attacker's login to
sysadmin.
"The lower-privileged user controls the instructions that the higher-privileged user executes via Copilot."
What the patch covers. Microsoft published CVE-2026-65669 on September 8, rated it critical, and lists SSMS 22.8.2 as the fix for the read-only bypass. Database instructions stay.
Microsoft's setting for running Copilot as a low-privilege user, agentExecuteAsUser, lives inside CONSTITUTION.md too. A database owner can write or drop it. Without a constitution, "GitHub Copilot runs queries under the connected user's login."
Agent mode is read-only by default. Switched to read-write, it runs changes after a click to approve, and Microsoft says that approval "isn't a security boundary."

Ship This Week.
Update SSMS to 22.8.2 or later wherever someone administers SQL Server.
List each database's stored instructions:
SELECT class_desc, major_id, minor_id, name, CAST(value AS nvarchar(max)) FROM sys.extended_properties WHERE name IN (N'AGENTS.md', N'CONSTITUTION.md');Use Copilot from a low-privilege login. A sysadmin session hands Copilot sysadmin. SSMS group policies can turn off Copilot, or only Agent mode.
List
db_owneranddb_ddladminmembers in databases our admins open with Copilot. Both can writeAGENTS.mdon any table, and owners can write the constitution.
Rule of the Week: a new Copilot instruction, then a new sysadmin
Every write to an extended property raises a SQL Server DDL event, a notice that a database's definition changed (Microsoft's list). Adding a login to sysadmin raises ADD_SERVER_ROLE_MEMBER, which SQL Server Audit's SERVER_ROLE_MEMBER_CHANGE_GROUP also records.
Our sketch is untested; Rehberger didn't publish one:
on CREATE_EXTENDED_PROPERTY, ALTER_EXTENDED_PROPERTY or DROP_EXTENDED_PROPERTY
where the property name is AGENTS.md or CONSTITUTION.md
then: log the login, the database and the property value; review it
on ADD_SERVER_ROLE_MEMBER where the role is sysadmin
then: alert, and look for an instruction change on that server in the week beforeCatch these with a DDL trigger or event notification at server scope, because a database owner can drop one inside their own database. Review a dropped CONSTITUTION.md too, since it takes agentExecuteAsUser with it.
Defender's Corner: keep pods away from the node's credentials
Remove or upgrade Attu 2.6.x, and block pods on EKS, Amazon's managed Kubernetes, from node credentials. Berenice Flores at Bishop Fox, "Zilliz / Attu | 2.6.5" [2026-09-29].
Attu is the web admin console for the Milvus vector database. Its Playground feature sends HTTP requests on the user's behalf, and it skipped the login check when a milvus-client-id header was missing. Its private-address filter checked the request's host field, while an HTTP:// address in the url field went through.
Flores used it to reach the node's instance metadata service, the internal address that hands an AWS machine its credentials. With the node's IAM role, kubectl signed in as system:node. A node can mint tokens for its pods' service accounts, their Kubernetes identities, and one had wide write access.
A pod shouldn't reach node metadata at all. AWS's EKS guide says nodes built by eksctl or the official CloudFormation templates allow both metadata versions with a hop limit of 2, which lets pods in. AWS's fix is IMDSv2 only with a hop limit of 1. The test node's role name started with eksctl-.
This week.
Find any internet-facing Attu. The 2.6.x line is no longer maintained, and the fix is 3.0.0.
List metadata settings in each region:
aws ec2 describe-instances --query 'Reservations[].Instances[].[InstanceId,MetadataOptions.HttpTokens,MetadataOptions.HttpPutResponseHopLimit]' --output tableWhere a node shows
optionalor a hop limit of 2 and no pod needs node metadata, set tokens torequiredand the hop limit to 1 in the launch template, or new nodes come back with the old values.
Agent Bench: test what our agent's allow rules let through
An allow rule approves a command by its text. Yang Wang, "Approval Laundering: Systematizing Approval–Execution Binding Failures in AI Coding-Agent Harnesses" [2026-09-30] measured how far that stretches in Claude Code 2.1.197, about 20 runs per test:
With
Bash(cat *)allowed, a fakecatplaced earlier onPATH, the list of folders the shell searches, ran instead of the real one in 20 of 20 runs.With an exact
git commit -m "wip"allowed, the repo's pre-commit hook, a script git runs before each commit, swept in an extra file in 9 of 20.A subagent, a helper the main session starts, reused the main session's approval in 18 of 19.
One control held: allowing the WebFetch tool never opened network access through the shell, in 19 runs.
The paper is a single-author draft, not yet submitted for review, and its runs inherited the author's own plugins and settings.
Run the first test in a throwaway VM: allow only Bash(cat *), put a cat script that writes a marker file ahead of the real one on PATH, ask the agent to read a file, and check for the marker from outside the agent.
What you walk away with: a list of our allow rules that a fake program or a hook can stretch.
Try it this week: search .claude/settings.json, .claude/settings.local.json and ~/.claude/settings.json for broad Bash(... *) rules on commands we treat as read-only.
Also on the Radar
Rohan Prabhu at StepSecurity, "SubQuery Ecosystem Compromise: Hidden Credential Theft and Backdoors" [2026-10-05].
@subql/common 5.8.3, a library in the SubQuery Web3 framework, shipped through the project's own release workflow from a throwaway branch, deleted before the package reached npm. One added step swapped the built package for an archive downloaded from ci-artifacts.dev, with no hash check. Neither commit reached main.
The payload runs on install and again on import, so --ignore-scripts leaves the import trigger. It's built to collect credentials, read secrets from GitHub Actions runner memory, and try AWS Secrets Manager and SSM Parameter Store across 17 regions. StepSecurity notes the GitHub events identify an account, not who controlled it. As of October 5, npm no longer lists 5.8.3.
If a lockfile resolves @subql/[email protected], rebuild that host and rotate what it could reach. For our own packages, set the npm trusted publisher's environment field to a GitHub environment only main can deploy to, and disallow tokens, so a publish from any other branch fails.
AWS Watch
CloudTrail now shows which data events we aren't logging. AWS, "Uncover blind spots in AWS data plane operations with CloudTrail Event Coverage" [2026-09-30]. Data events record object-level calls such as S3 GetObject, which a management-events trail leaves out. The new Event Coverage page in the CloudTrail console shows which services have data event logging on, per account or across an organization.
This week: open Event Coverage and close the gaps for services that hold customer data, such as S3, first. Data events are billed per event, so start where reads matter.
Would our logs catch any of these: a new Copilot instruction on a database, a pod reading node credentials, or a fake program on an allowed command? Hit reply and tell me.
Full issue with sources: join.defensive.works/p/your-database-can-tell-copilot-to-make-someone-sysadmin
Until next Tuesday,
R.K.
// end of issue 025
Sponsored content may appear below. Not part of Weekly Recon editorial.