Skip to content
osbytes
← back to blog

The developer convenience perimeter

2026-06-22by@osbytes9 min read
#security #opinion #tooling #supply-chain #ai

This blog has reached for the same phrase twice now without ever defining it. Once when LiteLLM's SQL injection landed on CISA's KEV list and the "routing detail" turned out to hold every upstream provider key. Once when JDownloader's download links were swapped and a CMS screen turned out to control what users execute. Both times the useful frame was the developer convenience perimeter: the set of tools, scripts, and services adopted to remove friction that end up holding credentials and routing trust — without ever being inventoried as perimeter.

That deserves a proper argument, because the pattern is much older than LLM gateways, and it is getting worse in a specific, traceable way.

The perimeter died; a new one grew in the tooling

In December 2014, Google's BeyondCorp paper made the canonical case that the network perimeter was indefensible: once an attacker is on the privileged intranet, the walls point the wrong way. The industry largely accepted the diagnosis. Zero trust became the stated posture at most companies big enough to have a stated posture.

But while security teams were dismantling the network perimeter on purpose, engineering teams were assembling a new one by accident. Every tool that removed friction — the coverage uploader piped into CI, the hosted build service that keeps your secrets so you don't have to, the package manager lifecycle hook, the GitHub Action pinned by tag because hashes are ugly — took custody of a credential or a trust decision as the price of convenience. None of these were adopted as security boundaries. All of them became one.

The defining property of this perimeter is that it is unaccounted. A firewall appears on an architecture diagram. The bash script your CI curls on every run does not, even when it can read the entire environment.

A decade of the same incident

The evidence for this isn't hypothetical. Line up the notable supply-chain incidents of the past decade and most of them sort into a small number of convenience shapes.

The script you pipe into your shell. For two months in early 2021, Codecov's bash uploader — the convenience that let thousands of teams ship coverage data with one curl — carried one added line that sent the full CI environment ($(env), plus git remotes) to an attacker's server on every run. The remediation advice was the tell: re-roll every credential your CI ever had in an environment variable. The uploader was never designed to hold secrets. It just ran where the secrets lived.

The service you gave your secrets so you wouldn't manage them. In January 2023, CircleCI told every customer to rotate any and all secrets stored on the platform after malware on one engineer's laptop stole a session cookie that survived 2FA. The whole value proposition of hosted CI is that you hand over your deploy keys and tokens so builds are frictionless; that concentration is exactly what made one laptop's compromise a rotate-everything event. Okta's October 2023 support breach is the same shape in miniature: support agents asked customers to upload HAR files — a browser debugging convenience — and those files carried live admin session tokens, which the attacker replayed against 1Password, BeyondTrust, and Cloudflare. The entry point, in turn, was a service-account credential an employee had saved into a personal Google profile that synced to a personal device. Convenience stacked on convenience, and the effective perimeter of an identity company ran through a browser password manager at home. LastPass had already demonstrated the endpoint version a year earlier: one of only four engineers with access to corporate vault decryption keys was compromised at home through an unpatched Plex media server, where a keylogger captured the master password after MFA had done its job.

The default one notch easier than the safe one. The March 2025 tj-actions/changed-files compromise (CVE-2025-30066) split its 23,000+ dependent repos into two populations with surgical precision. The attacker re-pointed the action's version tags at a commit that dumped CI runner memory — secrets included — into public workflow logs. Repos that pinned by commit hash were untouched. Repos that pinned by tag, the convenient default nearly everyone uses, got the payload. Homebrew's 2018 incident was the same economics on the maintainer side: a public Jenkins instance exposed a GitHub API token on its environment-variables page, and a researcher went from anonymous browsing to commit access on homebrew-core in about thirty minutes. Ultralytics in December 2024 added the archaeological variant: after the initial GitHub Actions cache-poisoning wave was cleaned up, a second malicious release went out through an old PyPI API token still sitting in a workflow — a leftover from before trusted publishing, never revoked because nothing forced anyone to.

The lifecycle hook that runs because installing should be easy. npm's install-time script execution is the purest distillation: code runs on your machine, with your credentials in reach, because that's what makes npm install feel like one step. September 2025's Shai-Hulud worm — the first self-replicating npm malware — ran TruffleHog on victim machines to harvest npm, GitHub, and cloud credentials, then used the stolen npm tokens to publish itself into every package the victim maintained. The November second wave reached roughly 796 packages with about 20 million combined weekly downloads, per Datadog's count as of late November 2025, and added a spiteful coda: if credential theft failed, it wiped the home directory.

The AI-era twist is acceleration, not novelty

I want to be careful with this claim, because "AI changed everything" is usually the lazy version. The convenience perimeter predates AI tooling by a decade, as everything above shows. What the current wave actually does is add new residents to the perimeter faster than previous waves did, and give some of them agency.

The August 2025 Nx "s1ngularity" compromise is the cleanest evidence. The malicious postinstall did the traditional things — scanned for wallets, SSH keys, tokens — but it also prompted whatever AI CLIs it found installed (Claude Code, Gemini, Amazon Q) to inventory sensitive files on the machine, then exfiltrated the loot through the victim's own authenticated gh CLI. Read that list of accomplices again: every one of them is a tool the developer installed to move faster, each carrying standing credentials or standing capability, each invisible on any perimeter diagram.

MCP servers extend the same pattern into standing infrastructure. Invariant Labs demonstrated tool poisoning in April 2025 — hidden instructions in a tool description, invisible in the UI, that walked Cursor into exfiltrating SSH keys — and a toxic agent flow against the official GitHub MCP server a month later, where a malicious public issue steered an agent into leaking private repo contents. The second one matters more, because it wasn't a bug in the server. The MCP connection itself is a standing credential with a language-model-shaped access policy. Every connected server is a new perimeter resident whose behavior is partially specified by whatever text it reads.

And the gateway pattern that opened this essay — LiteLLM holding every provider key because that's how multi-provider routing stays usable — is the same concentration CircleCI represented in 2023, rebuilt for model access in 2026. The scale trend is measurable: Sonatype's 2026 State of the Software Supply Chain report counts over 454,000 new malicious open-source packages in 2025 alone, more than 99% of them on npm, and describes campaigns increasingly optimized for developer workflows — credentials, CI secrets, build environments — rather than end users.

The counterargument worth taking seriously

There's a respectable school of thought that says convenience-shaming is security theater. Martin Tournoij's "Curl to shell isn't so bad" and Erica Windisch's earlier "curl | bash: a victimless crime?" both make the same sound point: piping an installer into your shell is not meaningfully more dangerous than git clone && make install. You already decided to trust the vendor; the delivery mechanism doesn't change that decision.

They're right about the single decision, and the incidents above don't refute them — Codecov's users would not have been saved by downloading the script instead of piping it. But the argument analyzes one trust decision in isolation, and the convenience perimeter is not one decision. It's the accumulation: each individually-rational adoption adds a resident inside your trust boundary, and no process anywhere keeps the roster. The tj-actions populations prove the point from the other side — the difference between compromised and safe wasn't whether teams trusted the action, it was a pinning convention nobody thought of as a security control until the day it was one. The problem isn't that any given convenience is reckless. It's that the sum has no owner.

Keep the convenience; keep the books

The wrong conclusion is friction-restoration: banning installers, hand-vendoring dependencies, making engineers miserable in the name of purity. Friction that's imposed rather than chosen tends to get routed around, which rebuilds the convenience perimeter one layer down where it's even less visible.

The right conclusion is accounting. If a tool can read secrets, publish artifacts, or execute during install, it's perimeter — put it on the inventory next to the VPN and the ingress rules, whoever adopted it and however small it looks. A few consequences follow directly from the incidents above:

Enumerate the residents. The Codecov line, the tag-pinned action, the leftover PyPI token, the AI CLI with a standing session — each was invisible because nobody's job was to list it. The question "what runs with access to our credentials?" should have a written answer that includes the glue, not just the services with logos.

Prefer the inconvenient pin where the delta is small. Hash-pinning actions, lockfile-only installs with scripts disabled by default, short-lived scoped tokens over long-lived broad ones. tj-actions and Ultralytics were both population-splitters: the safer convention existed, cost little, and cleanly separated victims from bystanders.

Treat standing credentials in agents and gateways as concentration risk. A model gateway holding every provider key, an MCP server with repo access, a coding agent with an authenticated gh session — these are the CircleCI shape again. They deserve the same treatment: scoped credentials, expiry, and a rotation plan you've actually rehearsed, because the incidents above suggest the question is when the rotation drill runs, not whether.

Assume install-time and debug-time surfaces are hostile-adjacent. Postinstall hooks, HAR files, CI environment dumps. If a workflow routinely moves secrets through a surface — even a support ticket — that surface is perimeter and should be minimized or scrubbed accordingly.

BeyondCorp's insight was that the perimeter you defend has to match the perimeter you actually have. A decade of incidents says the perimeter we actually have runs through coverage uploaders, lifecycle hooks, browser debug files, and now model gateways and agents — wherever friction was removed and custody quietly changed hands. The perimeter didn't die in 2014. It moved to wherever we stopped keeping the books.

Sources