The compromise of a widely used NPM package in December 2023 revealed vulnerabilities in GitHub workflows. This experiment shows how pull requests can expose sensitive data through modified workflows, highlights key findings, and suggests security measures to protect open-source repositories from exploitation.
In December 2023, it was discovered that an NPM package commonly used by decentralized web applications (dApps) had been compromised. The package in question, @ledgerhq/connect-kit, is maintained by Ledger, a well-known and arguably the most trusted provider of secure hardware wallets. Ironic right?
Well, not really, because the compromised package has nothing to do with the ledger's secure hardware wallets.
However, the incident understandably raised concerns among users about the security of their assets, despite those assets being stored offline in hardware wallets. While the compromised package posed no immediate threat to Ledger's hardware devices, the situation sparked widespread discussion and speculation.
The prevailing theory suggests that the compromise occurred due to a vulnerability in Ledger’s GitHub workflow. It is believed that an attacker exploited a GitHub pull request workflow to gain access to Ledger's NPM keys, enabling them to publish malicious code. The malicious update reportedly caused a secondary window to open when users attempted to connect their wallets.
The Experiment
The incident piqued my curiosity, prompting me to question whether GitHub workflows were inherently flawed or if there was more nuance to the exploit. To explore this, I conducted an experiment to see if I could replicate the vulnerability.
Using an existing open-source repository, I attempted to recreate the exploit. During my testing, I discovered that:
1. A pull request can edit a workflow and the new workflow will run immediately after the pull request is made
The screenshot below displays the contents of a pipeline.yml file from the repository I was working with. The pipeline is configured to trigger every push to the main branch, deploying the serverless application to AWS.
I proceeded by creating a new branch within the repository and modifying the pipeline file. The updated configuration was set to trigger the workflow on every pull request, regardless of the branch. The screenshot below illustrates the modified state of the file.
Along with these modifications, I added an instruction to print the AWS_REGION GitHub secret, which was already present in the repository. I expected to see the value displayed in the workflow logs after the action was executed successfully.
I then submitted a pull request to the main branch with these changes, and as expected, the modified workflow was triggered and executed successfully, even though the pull request had not been reviewed, approved, or merged! Interesting.
As seen in the screenshot above, the workflows triggered by my pull request were executed successfully. You might notice there are two workflow runs displayed, which I will address in the next section. For now, let's focus on the workflow labeled "test: modified GitHub workflows" at the bottom.
Once the workflow was completed, I reviewed the logs, and as expected, the AWS_REGION GitHub secret was masked, as shown in the following image. This outcome was anticipated, as I had previously encountered a similar article detailing this kind of exploit, which informed my approach to this experiment.
Now, if the secrets were concealed, how did the attacker manage to access them? This question led to my second key finding:
2. GitHub secrets can be exposed by making curl requests to third-party APIs within a modified workflow
Yeah, you read that right! To test this, I further edited the workflow to include a request to a RequestBin I created on . The screenshot below illustrates the updated workflow.
This explains the second workflow run shown in the earlier screenshot, confirming that both workflows were executed successfully.
On Pipedream's RequestBin, I was able to view the GitHub "secret" in plain text. This raised a concerning question: could anyone simply submit a pull request to an open-source project and easily access sensitive keys?
Securing Your Workflows
Given the potential vulnerabilities uncovered during this experiment, it’s crucial to understand how to secure GitHub workflows to prevent unauthorized access to sensitive data. GitHub provides several settings that can be configured to reduce the risk of exploitation:
Actions permissions setting:
By default, all actions are permitted to run, regardless of the author. For enhanced security, this setting should be updated to limit permissions, ensuring that only trusted workflows can execute.
Fork pull-request workflows from outside collaborators setting:
This setting defines which outside collaborators require approval to run workflows in pull requests. Properly configuring this setting is critical, as misconfiguration could expose your repository to potential exploits.
Additionally, GitHub’s documentation notes that workflows triggered from forks do not have access to sensitive data like secrets. This emphasizes the importance of reviewing the settings for repositories where sensitive data is handled.
By implementing these security measures, repositories can significantly reduce the likelihood of similar vulnerabilities being exploited.
Possible Explanations for the Exploit
Taking all of the above factors into consideration, if the rumors are accurate and Ledger's NPM secrets were indeed compromised, a few scenarios might explain how this occurred:
CASE #1: The package maintainers overlooked the configuration settings and allowed the compromised workflows to run.
CASE #2: The attacker somehow obtained full write access to the repository.
CASE #3: The attacker is, or was, a previous contributor to the project.
CASE #4: The exploit was carried out as an inside job.
My Analysis
Upon reviewing these scenarios, I believe that CASE #3 is the most plausible explanation. A previous contributor may not need explicit approval to trigger workflows in the repository, making it easier to exploit this vulnerability.
I have seen various discussions on social media suggesting that a former employee’s account might have been compromised, which would support CASE #3. However, until an official statement is released by Ledger, the exact cause remains speculative.
Final Thoughts
Through this experiment, I gained a deeper understanding of how workflow vulnerabilities can be exploited and how developers can protect their repositories from such threats. By implementing the recommended security settings and thoroughly reviewing contributor permissions, open-source maintainers can minimize the risk of unauthorized access.