October 31, 2026
Your AI Coding Assistant Will Run Whatever Its Config File Says
[bug bounty hunters and appsec engineers] This month, a single trailing dot in GitHub Copilot’s own security prompt was turned into a…

By Gopal Rajguru
9 min read
[bug bounty hunters and appsec engineers] This month, a single trailing dot in GitHub Copilot's own security prompt was turned into a remote code execution vulnerability.
AI coding tools are a great boon to any bug hunter. They have access to files that you can control, will write to files on the user's disk, and run processes. All the kill chain is in one place here, and most of these tools were rushed to production with security being a v2 concern.
In October, the Cloud Security Alliance finally coined a term for this — the MCP launch path. This is when an AI client takes data-like input (such as a config entry or OAuth metadata) and turns it into running a process on your machine. This month there were two bugs found exploiting this. One was the trailing dot in Copilot (CVE-2026–103572). The other was a terminal agent named opencode that would pass a crafted URL directly to PowerShell.
Both of these aren't memory corruption or some fancy web exploitation. They're both exploiting the difference between what the tool was validating, and what it was running. I think this is one of the more interesting areas to look in at the moment, and almost nothing is being written about it. Let's walk through both of these, what they have in common, and how I'd look to find another.
TL;DR
AI coding assistants parse configuration and metadata to trigger processes. However, two vulnerabilities were discovered this month that turned this into arbitrary code execution. This post will cover:
- How the execution path works and how your configuration files and OAuth metadata are effectively command lines.
- Copilot CVE-2026–103572 — One extra dot bypasses the confirmation check.
- opencode (No CVE) — A valid https URL but is actually a PowerShell command. Two repeat offenders.
- The root cause — Validate one format and execute another.
- Hunting checklist.
- Reporting — Scope fudging, silent patches and how to report the impact.
No memory corruption or interesting web vulnerability, it's simply a discrepancy between what is being validated and executed.
What is a launch path?
Quick Background MCP (Model Context Protocol) is the way your AI assistant communicates with external tools. These tools could be a filesystem, a browser, an API, etc. Each of these tools will be an MCP server, and your client will know about them via a config file (usually a JSON file). The client will load this file during startup.
There are two types of server, both of which have a place to put your data so that it can be run. The first is a stdio server. This will be a local process. The config file will contain a line telling it to run the binary with the given arguments. This line is known as the launch path. It is loaded by the client and used to start the process. There is no ambiguity here, it is intended to be run. The second is a remote server. This will communicate via HTTP. When you log in it will open a browser to the URL specified by the server's authorisation_endpoint. On some platforms this will result in the URL being opened by the shell. This is your second launch path.
The CSA's one liner: The launch path is a way of turning your config and discovery metadata into a command line. The agent believes it is reading a description, however the OS sees it as a command.
This makes the attack very simple. You don't need to trick the user into running a command. You simply need to get your string into one of the two places and let the tool run the command. After all, that's why it exists!
Trailing dot: Copilot CVE-2026–103572
My favourite due to how trivial the vulnerability is.
The Copilot agent has edit access to your files but it was decided that the most dangerous files (.mcp.json, settings.VisualStudio.json) should not be writable without user confirmation by clicking "yes, I'm sure." The issue was that during this confirmation a simple string comparison was used to see if the file name was protected.
The issue was that on Windows the file system strips off the trailing dot from the file name. The agent attempts to write to .mcp.json (with the extra dot). This is then checked against the string and as it doesn't match .mcp.json it is allowed to proceed. The file is then written to by the Win32 layer and the dot is stripped off. This results in the contents being written to .mcp.json.
The string comparison was only checking the file name. The OS was then writing to a different file. Microsoft fixed this by using GetFullPath to normalise the file path before doing the string comparison.
Writing to a file alone doesn't constitute RCE. To achieve this we combine this with indirect prompt injection. We can feed the agent a poisoned README/issue/dependency file as context. The instructions within the file will tell the agent to write a malicious MCP server definition to .mcp.json without needing confirmation. The server will then be launched automatically by the IDE. Visual Studio also has a second door into this room by changing the ripgrepPath setting. This will cause your binary to run next time someone does a search within the editor.
CVSS 8.8, Important. Reported by Johann Rehberger on August 4th. Patched on Patch Tuesday (13th October) in versions 17.14.42 and 18.10.4. This vulnerability is in a common DLL (Microsoft.VisualStudio.Copilot.Core.dll) so SQL Server Management Studio is also affected. No overflow or primitive just a string comparison trusting a file name that the OS would change.
When a URL is an command: opencode
The second example is the reverse scenario where the remote OAuth example was never assigned a CVE. I'll get onto that shortly.
This vulnerability was in the open source terminal coding agent opencode. It connects to a remote MCP server and fetches the OAuth discovery metadata. The authorisation_endpoint was then passed to the open npm package to open a browser for authentication. The issue here was that the authorisation_endpoint returned by the server was a valid https:// URL. This passed the new URL() check, however the URL contained a PowerShell payload.
The reason this was possible was due to the pinned version of open (10.1.2) on Windows and WSL generating the powershell -EncodedCommand command and passing the URL as a quoted string. PowerShell will evaluate the $(…) subexpression inside double quotes. So a URL shaped like https://host/$(...) and pass all URL checks, before being executed as a command. This did not affect macOS or Linux as they behave differently with the open command.
The fix (1.18.33, 28th September) was to upgrade open to version 11.0.4. The argument is now quoted with single quotes and a specific opener has been added with a scheme check. Something I love about this fix was that the researchers noted that the scheme check would not have prevented this as the payload was a valid https URL. The real fix was the quoting. The vulnerable versions were between 1.0.137 and 1.18.32.
This sink is recurring. The pattern of passing an untrusted authorisation_endpoint to the open package and Windows shell is clear. mcp-remote had this vulnerability (CVE-2025–6514). This was discovered by JFrog and had a CVSS score of 9.6. It was fixed in version 0.1.16. openmcp-client (VS Code extension) had this vulnerability (CVE-2025–58062). This had a CVSS score of 7.3 and was fixed in version 0.1.12. This was present in three different products. The lesson here is that if you find this vulnerability in one product, check any sibling tools that also use the same library as there is a high chance that one of them will not have been patched.
Summary
Removing the product names from both bugs gives:
The check used a different version of the value.
In both cases, the validation was present but occurred on the wrong format. Copilot was checking the filename but the OS was executing the canonicalised version of the path, with the dot removed. opencode was validating the URL format, but the shell was executing the raw string with the subexpression intact.
This is classed under the general concept of 'trust handoff'. There's a handoff between two components (JSON to filesystem, URL parser to shell). Each component assumes the previous component has done the validation. No validation occurs on the correct format.
For hunting, this changes everything. We're not looking for missing validation (which is easy and rare). We're looking for 2 layers being silent about a string. We can have validation just before the path operation (string comparison), validation just before the raw bytes are passed to the shell (parsed object validation), or allowlisting just before the argument is quoted. Any point where the validation and execution components have different versions of the value are candidates.
How I would hunt this bug
Find an AI coding agent, MCP client or IDE assistant. Most are open source which is nice. You're always going to be looking for a string that the attacker can influence, which results in a process being launched. Start by finding where processes are being launched. Grep for common functions in the source (spawn, exec, execFile, child_process, open, start, ShellExecute, powershell, cmd /c). These are your sinks. Work backwards from each of these.
You'll generally see that they're being populated by config or discovery data. MCP server definitions (command, args, env vars), OAuth discovery (authorization_endpoint, token_endpoint, registration_endpoint), or any setting where you're defining a binary to run (ripgrepPath, formatters, linters, shells).
If you're using validation to determine if a file should be written or a binary should be run based on the name, you can try using some of the Windows filename quirks. Add a trailing dot, trailing space, ..\ traversal, 8.3 short name, use the \?\ prefix, or add an alternate data stream. Try to cause a mismatch between the validation and OS.
If you're validating a field as a URL and passing it to an opener, keep it a valid URL but add shell metacharacters to the path or query (Windows only). $(…), backticks, ;, &. Remember opencode. Just validating the scheme won't help if it still parses as https.
Most of these will require the agent to create the malicious config. This is where prompt injection comes in. If you can inject text into the model's context (README, issue, comment, dependency manifest, tool output) and the model can create files, you've got your vector. Don't forget the enable/disable flags. Sometimes the last step is to enable an attacker's server on their system.
The pain points
This is an honest answer. This bug has a problem with scope and will cost you. A common response is 'malicious MCP servers are out of scope'. opencode's maintainer said pretty much this. They acknowledged the report, said malicious servers were out of scope, fixed the same day, no CVE or advisory. Microsoft confirmed the Copilot bug, fixed it on Patch Tuesday… but said it was out of scope for a bounty. Expect this!
To get past triage, don't think about it as a bad server. Think about it as untrusted metadata being passed to a shell, or unpriviledged writes bypassing a control implemented by the vendor. The confirmation prompt from Copilot is the vendor confirming that they should have a control to require consent for this write. You're not saying the server was naughty, you're saying you've bypassed their own control.
Show the full path to attacker controlled input. If you can use prompt injection to create a poisoned repo/issue/dependency, you can say the user opened a malicious repository rather than 'the user configured a bad server'. This is outside of anyone's threat model. Be specific with the impact. RCE in context, persistence via config, lateral movement using the agent's credentials.
Just because there's no CVE, doesn't mean there's no fix. Many of these had silent fixes. If you're using CVE feeds you'll miss them. Check the version of the installed package directly. Also, a clean write up of a silent fix is a form of currency.
If you're the maintainer/defender
Short answer. Fix it by: Always canonicalising. Any validation that will determine if a file should be written or a process launched based on the name should canonicalise the path using the OS. Never validate the raw string from the user. This is the whole issue with Copilot.
Treat config/discovery data as code. Any setting where you can define a binary or URL to open (.mcp.json, IDE settings, OAuth metadata) is effectively a command line in disguise. Ensure that any changes made by the agent require human review. Keep an eye on the enabledMcpServers and binary path settings.
If you're using a URL opener as a sink, ensure you're using proper quoting or an array format (execFile). Don't use a scheme allowlist. Even if it's a valid https URL, it could contain a shell payload. opencode learned this lesson. Also, know what version of open (or whatever browser launcher you're using) you're on. How does it quote on Windows? 10.x to 11.x is the exact issue.
If you're blue teaming, look for processes from your coding agents (devenv.exe, ssms.exe, opencode, Node, Bun) launching powershell.exe with -EncodedCommand. Don't limit yourself to one image name. The agent will run under multiple names. Add the agent's config files to your assets to monitor. Any changes to them should be treated as code changes.
Conclusion
We've spent the last decade training developers to be wary of user input. However, AI agents have hidden the danger in plain sight. We now have config, metadata and something with permissions to launch processes on our machine. The launch path issue is simply a tool that's designed to run commands trusting a string that hasn't been re-validated.
This is a blessing for hunters. There's a huge surface area, most are open source, and are getting deployed weekly. They're easy to find using grep and some Windows filename tricks. The only real pain point is the scope. If you write your reports to highlight that the vendor has a broken control then you'll be fine.
Pick an MCP client this week and find where processes are being launched. There's a trailing dot waiting for you.
If you found this useful I write up bugs I find in web and AI tooling. Follow me and if you've seen this pattern in any other tools let me know in the comments!