Responsible disclosure of an unauthenticated RCE in GitHub Copilot CLI before 1.0.26. Reported in March, I found this bug with Opus 4.6 before the nerfs. There was no CVE/GHSA issued.
TLDR: no auth on port, port exposed on network, and tool permission confusion allowed remote command execution
Preconditions:
Victim: runs "copilot --acp --port <p>"
Attacker: has reachability to TCP port
A bad actor could chain flaws from missing network/copilot auth, to node misconfiguration, and ACP misunderstanding. I was impressed with Opus 4.6 ability to bring these concepts together (with some nudging). The result is unauthenticated remote code execution from a reachable network position.
My logs show research on GitHub Copilot CLI began at 10:19p. The session started with the objective to find bugs in newer features of GitHub Copilot CLI. The idea was simple: fast moving = break easy.
Before any real analysis, recon and threat modeling was needed, so I asked Opus 4.6 to decompile the GitHub Copilot CLI. It is not open source. Opus 4.6 handled the decomp easily, then performed source code mapping and initial static analysis.
Finding 1. No Auth: there is (was?) no authentication or authorization on any requests sent to the GitHub Copilot CLI ACP Server port. The client never sends their own credentials and there is no request origin checking. Every unauthenticated client piggybacks on the GitHub Copilot credentials of the server for AI requests.
It wasn't until 12:11a that Opus 4.6 made this first breakthrough. The two-hour span was real honest work of mapping the surfaces and looking elsewhere. The bug was found after Opus 4.6 spawned a subagent tasked with "copilot --acp --port, bind behavior, client auth, and permission implications."
Finding 2. Node Misconfiguration: the first finding wouldn't be so bad if it was same-device service access, but there was a Node misconfiguration, which bound the GitHub Copilot CLI ACP Server host to 0.0.0.0: a wildcard for all network listener interfaces, including local, external, and public. As a result, the service was exposed across the network. No other protocols in the client were found to use this binding.
Coupled with the first find, a remote attacker could send unauthorized requests to a victim's GitHub Copilot CLI and use their paid features: start sessions, send chat messages, attempt tool calls, etc. At this point, I also needed to sign up a GitHub Copilot account for testing, so I did (cancelled later).
Opus 4.6 found this bug at 12:40a, only 29 minutes after the first finding. This was discovered after writing targeted prompts for other flaws in the ACP implementation, with a focus on bugs that may chain together. Again, this was found by a subagent.
Several reachability checks were also tested and completed by 12:48a. Cool, but there is no RCE yet, only remote access to a service.
Finding 3. ACP Misunderstanding: the only real "authorization" was at Copilot CLI ACP Server's LLM tool call layer. Breaking this authorization was important because through tools, a remote client can run shell commands. I audibly laughed when Opus 4.6 broke this.
By default, tool calls through the Github Copilot "--port" are limited unless the CLI user also runs with the "--allow-all-tools" argument. Safe, right? Well...
Copilot CLI uses a shared permission scaffolding between protocols, so the program only needs to handle a standard set of permission args (like "--allow-all-tools"), JSON formats, etc. And you may note I said tool calls are limited, not disabled.
When limited ("--allow-all-tools" is missing), Copilot delegates to the protocol of the server for tool permission, ACP in this case, and the ACP protocol... asks the client for permission. It is even in the name: Agent Client Protocol, the client is in charge.
In other words: a malicious unauthenticated remote client sends their shell command to the victim ACP server, the server says "this needs permission", and then sends the permission request to the malicious client, who approves their own requested shell command, and the command is then executed on the victim server.
There was an apparent assumption by GitHub developers that the protocol has server-side or non-client approvals, and that would act as its own authorization. For most server agent protocols, that may be the case. However, ACP has a hyperfocus on client control and this was not properly considered.
This final finding was discovered at 1:34a, nearly an hour after the second finding, was a two-parter. First was the permission bypass, from my logs, "ACP delegates session/request_permission to the connected client, so a malicious client can return allow_always". Second, only 2 minutes later, confirmed it works even when "--allow-all-tools" is missing.
I worked on the report and PoC deeper into the night, including a PoC which prints the victim system info from a remote position, and wrapped up this effort at 2:47a.
It was a lot of fun to find this RCE vulnerability, and I'm glad the core issue is patched. Watching Opus 4.6 create threat models, gravitate toward security-sensitive code (after decompiling programs on its own), and chain together findings was truly novel; this was before Mythos' announcement in April.
That said, I am done with the GitHub program. Beyond the bounty being less than 10% of advertised (10k-20k listed, received the program minimum of 617): triage took 7 weeks, not all issues were addressed, and core impact seems to be ignored.
The bug hunting process was awesome, the reporting process was awful.