Latest Posts (2 found)
crtns 1 months ago

On Being Blocked From Contributing to lodash

My Github account was blocked from contributing security improvements to the lodash project. This was my first open source work in a while, and unfortunately, it appears it was a waste of time. That said, I did learn a few lessons about contributing to open source projects that others might benefit from. I've been going down a rabbit hole to figure out how to improve supply chain security in the JavaScript ecosystem. A common problem is the inability to trust the true origin of code within a package and how that package was built and published. Phishing attacks on npm registry users exploit this weakness - threat actors with stolen credentials will directly publish malicious package versions to the npm registry, bypassing CI/CD entirely. A consumer of the package will be none the wiser. will happily install the malicious package version if configured to do so. One way to detect this type of attack is through package provenance. Publishing packages with provenance is the process of creating a signed statement of attestation during the building of a package so that the build process can later be verified. The statement of attestation contains metadata about the build, provided in part by a trusted CI/CD platform, like Github Actions runners. While not a security panacea, dependent projects can check the statement of attestation to detect whether a package was published by a trusted CI/CD process or directly uploaded to the artifact registry, bypassing CI/CD. The npm client itself has made the process of generating and publishing a statement of attestation trivial - all you need is a Github Actions workflow that runs the command with these flags. For packages that already use Github as a code forge, adopting a workflow to publish packages with these additional flags is, in most cases, a low-effort task. Despite this, the adoption of package provenance appears abysmally low. Of the ten most popular packages on the npm registry, only two are published with provenance. Even the package is not published with provenance. I've always felt like an outsider in the world of open source - mostly a consumer, not a contributor. It occurred to me that since I value having npm packages published with provenance, I could be the one to push those PRs. This could be my way of giving something back. Among the top ten packages on npmjs.com without provenance, lodash was the one that caught my eye. I have used lodash many times, both professionally and personally. What stood out specifically about it is that there has not been a new release in over 5 years, but it's still being downloaded tens of millions of times per week. When I went to the Github repo, I saw the main branch had not received a new commit in 9 months. When I checked for a workflow to publish the package, I found nothing. I saw what I thought was a good opportunity. I was certain I could figure out the build process, create a new Github Actions workflow to automatically build lodash, and add provenance to boot. I figured if my initial PR was rejected, I could at least start a conversation about supply chain security and reproducible builds for this very popular project. Within a few hours, I had a workflow that was mostly working. I reverse-engineered the packaging workflow by digging through git history, reading docs and the wiki. I even managed to publish a forked version of lodash to npmjs with provenance after some trial and error. Unfortunately for me, that trial and error included opening a PR against the lodash repo before I was ready. I quickly closed the PR because I realized that the build artifacts in my version were not quite a 1-to-1 match with what was in the latest build of lodash. I spent a few more hours in vain trying to figure out how to replicate the build. Eventually, I called it a day and decided to open an issue in the morning to ask the last maintainer who published a build how they managed to generate it. I quickly typed up a Github issue the next morning and pressed "Create". Nothing happened. I looked around and saw an error I had never seen before on Github: "Error - Failed to create the issue." I figured Github was having an outage, so I took a break and did something else. When I tried again though, I saw the same error repeatedly, even after changing the title and content of the issue several times in the off chance I was triggering some kind of blocklist. I decided to try and reproduce the issue in my own repository. No error - I was able to create a Github issue successfully. At this point, I suspected something was up specifically with lodash but I wasn't sure what. I went back to my closed PR on a hunch and noticed some new activity. The PR, despite being already closed, was locked and limited to collaborators. At this point, I was fairly certain I had been blocked. What finally gave it away was when I tried to use the watch action on the lodash Github repo, I got a truly bizarre and nonsensical error - I couldn't watch more than 10,000 repos on Github. I don't even watch 100 repos, and I could watch any other repo I wanted, outside of the lodash organization. In an attempt to reach out to clear up any misunderstandings, I opened a Github issue on my forked repo, tagged the lodash org and primary maintainer, and explained the situation. I gave context as to why I had opened the PR, and what I wanted to achieve. Two weeks later, no response. As a last-ditch effort, I sent an email directly to the same primary maintainer, using an email I found in git commit history, but I have also received no response there either. At this point, I believe I've been permanently blocked. While the effort I ultimately put into this project appears not to have furthered my goals, at least this was a learning experience. My contributions being rejected reinforces a belief I already held before going into this project - open source maintainers don't owe me anything. That said, I'm still confused as to why I was blocked for opening a single PR. I wanted to spark a conversation on how to publish a new version of lodash and ultimately make the build process transparent and trustworthy. I'm genuinely curious if my PR was viewed incorrectly as malicious, or if the maintainer who blocked me simply has no interest in what I was trying to do and is signaling that to the lodash community. When I have time, I will continue to try and add provenance to open source NPM packages where I believe there is value, but I will start slowly and open an issue first to discuss the change. If there's interest, I'll create a pull request. If I'm ignored, I'll move on. My mistake with lodash was jumping in headfirst without gauging the interest of the maintainers or getting a better sense of what was happening in the project. I found out after the fact that the primary maintainer of lodash declared "issue bankruptcy" back in 2023 , closing a slew of open Github issues and starting from scratch, and that a major rewrite of the codebase seems to have stalled out with no progress in 11 months. While the CONTRIBUTING.md in the repo indicates "Contributions are always welcome", I mistakenly believed that demonstrating enthusiasm through a pull request was the best way to contribute to open source. I should have known better. As a professional software engineer, I've learned this lesson before: more effort upfront doesn't guarantee results. A five-minute conversation to gauge interest can save hours of work on an unwanted PR.

0 views
crtns 2 months ago

Why I Moved Development to VMs

I've had it with supply chain attacks. The recent inclusion of malware into the package was the last straw for me. Malware being distributed in hijacked packages isn't a new phenomenon, but this was an attack specifically targeting developers. It publicly dumped user secrets to GitHub and exposed private GitHub repos publicly. I would have been a victim of this malware if I had not gotten lucky. I develop personal projects in Typescript. I've used . Sensitive credentials are stored in my environment variables and configs. Personal documents live in my home directory. And I run untrusted code in that same environment, giving any malware full access to all my data. First, the attackers utilized a misconfigured GitHub Action in the repo using a common attack pattern, the trigger. The target repo's is available to the source repo's code in the pull request when using this trigger, which in the wrong case can be used to read and exfiltrate secrets, just as it was in this incident. 💭 This trigger type is currently insecure by default . The GitHub documentation contains a warning about properly configuring permissions before using , but when security rests on developers reading a warning in your docs, you probably have a design flaw that documentation won't fix. Second, they leveraged script injection. The workflow in question interpolated the PR title directly in a script step without parsing or validating the input beforehand. A malicious PR triggered an inline execution of a modified script that sent a sensitive NPM token to the attacker. 💭 Combining shell scripts with templating is a GitHub Action feature that is insecure by design . There is a reason why the GitHub documentation is full of warnings about script injection . A more secure system would require explicit eval of all inputs instead of direct interpolation of inputs into code. I'm moving to development in VMs to provide stronger isolation between my development environments and my host machine. Lima has become my tool of choice for creating and managing these virtual machines. It comes with a clean CLI as its primary interface, and a simple YAML based configuration file that can be used to customize each VM instance. Despite having many years of experience using Vagrant and containers, I chose Lima instead. From a security perspective, the way Vagrant boxes are created and distributed is a problem for me. The provenance of these images is not clear once they're uploaded to Vagrant Cloud. To prove my point, I created and now own the and Vagrant registries. To my knowledge, there's no way to verify the true ownership of any registries in Vagrant Cloud. Lima directly uses the cloud images published by each Linux distribution. Here's a snippet of the Fedora 42 template . Not perfect, but more trustworthy. I also considered Devcontainers, but I prefer the VM solution for a few reasons. While containers are great for consistent team environments or application deploys, I like the stronger isolation boundary that VMs provide. Container escapes and kernel exploits are a class of vulnerability that VMs can mitigate and containers do not. Finally, the Devcontainer spec introduces complexity I don't want to manage for personal project development. I want to treat my dev environment like a persistent desktop where I can install tools without editing Dockerfiles. VMs are better suited to emulate a real workstation without the workarounds required by containers. Out of the box, most Lima templates are not locked down, but Lima lets you clone and configure any template before creating or starting a VM. By default, Lima VMs enable read-only file-sharing between the host user's home directory and the VM, which exposes sensitive information to the VM. I configure each VM with project specific file-sharing and no automatic port forwarding. Here's my configuration for . This template can then be used to create a VM instance After creation of the VM is complete, accessing it over SSH can be done transparently via the subcommand. The VM is now ready to be connected to my IDE. I'm mostly a JetBrains IDE user. These IDEs have a Remote Development feature that enables a near local development experience with VMs. A client-server communication model over an SSH tunnel enables this to work. Connecting my IDE to my VM was a 5 minute process that included selecting my Lima SSH config ( ) for the connection and picking a project directory. The most time consuming part of this was waiting for the IDE to download the server component to the VM. After that, the IDE setup was done. I had a fully working IDE and shell access to the VM in the IDE terminals. I haven't found any features that don't work as expected. There is also granular control over SSH port-forwarding between the VM (Remote) and host (local) built in, which is convenient for me when I'm developing a backend application. The integration between Podman/Docker and these IDEs extends to the Remote Development feature as well. I can run a full instance of Podman within my VM, and once the IDE is connected to the VM's instance of Podman, I can easily forward listening ports from my containers back to my host. The switch to VMs took me an afternoon to set up and I get the same development experience with actual security boundaries between untrusted code and my personal data. Lima has made VM-based development surprisingly painless and I'm worried a lot less about the next supply chain attack.

0 views