One Maintainer's Unmerged Pull Request Exposed a CI Token Leak That Was Active for Eight Months

Jul 17, 2026 By Deepa Iyer

A lone maintainer was debugging a flaky CI job when they noticed something odd in the build logs: an environment variable named PROD_DEPLOY_TOKEN was being echoed in plaintext. The token, scoped to write access on a popular npm library's repository, had been exposed for eight months. The pull request that introduced the leak was never merged—it sat unreviewed, abandoned by a contributor who had moved on. By the time the maintainer spotted it, the token had rotated twice, but the leak window spanned over 240 days. This is not a rare incident. It is a symptom of how CI pipelines are built, reviewed, and ignored.

The Pull Request That Was Never Merged

The discovery happened during a routine CI debugging session. The maintainer, who prefers to remain anonymous due to past harassment, was tracing a failed job in a GitHub Actions workflow. The logs showed a step that printed all environment variables for debugging—a common practice in early-stage development. Among the variables was PROD_DEPLOY_TOKEN, a credential used to push releases to a package registry. The token was visible in plaintext, accessible to anyone who could view the log output.

The maintainer traced the variable back to a pull request opened eight months earlier by an occasional contributor. The PR aimed to add a new CI job for automated deployment. The contributor had defined the token as a repository secret but also echoed it in a debug step, presumably for testing. The PR was never merged—it was left open, with no reviewer comments, no merges, no activity. Yet the token exposure persisted because the CI configuration file that contained the echo statement was still present in a branch that could be triggered manually.

The token itself was a personal access token with the repo scope, granting full control over the repository including the ability to push commits, create releases, and modify workflows. An attacker who obtained it could have injected malicious code into the package, affecting thousands of downstream users. The maintainer revoked the token immediately, but the incident raised uncomfortable questions: How many similar tokens are leaking right now, unnoticed?

The PR's abandonment is a familiar story in open source. Contributors drift away, maintainers are overwhelmed, and low-priority changes languish. The PR had no labels, no assignee, and no automated checks beyond basic linting. It was simply forgotten.

How a Leak Survives Eight Months Undetected

The leak persisted because no automated secret scanning was applied to CI logs. GitHub's secret scanning, as of early 2025, covers committed code but not ephemeral CI output. The logs were stored for 90 days by default, but the token was printed in every run of that branch, so it appeared repeatedly. No alert was triggered because the pattern—a token echoed in a debug step—did not match known formats like ghp_* or sk-*.

Human review was skipped because the PR was never assigned. The project had a policy of requiring at least one reviewer for changes to the CI configuration, but that policy was not enforced. The PR sat in a queue of hundreds of open issues and pull requests. The maintainer who eventually discovered the leak was not the same person who had reviewed previous CI changes—they were simply the one who ran the job that failed.

The token was rotated quarterly, but the leak predated the rotation cycle. An attacker who had scraped the logs at any point in the eight-month window could have used the token until the next rotation. Even after rotation, the new token could have been exposed in the same way if the debug step was still active. The project's rotation policy was manual and did not include checking for exposed secrets in logs.

The compromise window—the time during which an attacker could have exfiltrated the token and used it—was at least 240 days. During that period, the repository had 12 releases, each of which could have been tampered with. No evidence of malicious activity was found, but the maintainer acknowledged that an attacker could have silently cloned the repository, extracted secrets, and used them without leaving obvious traces.

The Economics of Ignoring Supply-Chain Security

Why do such leaks persist? The answer is partly economic. A dedicated security engineer costs roughly $200,000 per year in total compensation. Many startups and mid-sized companies skip this line item, relying on existing engineers to handle security as a side task. Open-source projects have even less budget—they depend on volunteer maintainers and occasional grants.

The average cost of a software supply-chain breach, according to a 2024 industry report, is around $2.4 million when factoring in remediation, legal fees, and reputational damage. That is roughly 12 times the annual salary of a security engineer. Yet the upfront cost of hiring such an engineer is visible on a balance sheet, while the risk of a breach is deferred and uncertain. Venture capital pressure to ship features quickly compounds the problem—CI pipeline security is rarely a priority in sprint planning.

Open-source maintainers bear the monitoring burden disproportionately. A 2025 survey by the Linux Foundation found that 60% of maintainers spend less than five hours per week on security-related tasks. They are expected to review code, manage secrets, and respond to vulnerability reports, all without compensation. The token leak described here was discovered only because a maintainer happened to look at the logs—not because a systematic process caught it.

The economics also explain why commercial secret scanners are not universal. A GitHub Advanced Security license costs roughly $49 per contributor per month. For a project with 50 active contributors, that is nearly $30,000 per year—a sum that many open-source foundations cannot justify. Free tiers exist but often lack coverage for CI logs.

Real-World Fallout: What a CI Token Unlocks

A CI token with write access is a skeleton key. In this case, the token could push commits to the main branch, create releases, and modify GitHub Actions workflows. An attacker could have added a malicious step to the CI pipeline that exfiltrated other secrets, such as cloud storage credentials or API keys for downstream services.

The token also allowed access to the npm registry where the library was published. An attacker could have pushed a new version containing a backdoor, a pattern seen in the 2024 PyPI token compromise, where a leaked token allowed an attacker to publish malicious packages under a legitimate account. The same technique could have been used here, affecting any application that depended on the library.

Dependency confusion attacks are another vector. If the token granted access to a private registry, an attacker could upload a package with the same name as a public dependency, tricking build systems into using the malicious version. The token's scope was broad—it was created for convenience, not least privilege. This is a common anti-pattern: tokens are often over-scoped to avoid the hassle of managing multiple credentials.

Downstream repositories that forked the project or used it as a dependency were also at risk. A malicious commit pushed to the main branch would propagate to all forks that synced upstream. The maintainer estimated that the library was used by roughly 500 other open-source projects, based on dependency graph data. A single compromised token could poison thousands of builds.

Why Current Tools Miss These Leaks

Existing secret scanners are designed for committed code. They scan git history for patterns like -----BEGIN PRIVATE KEY----- or ghp_ tokens, but they rarely inspect CI logs. GitHub Actions logs are stored as plain text and are not indexed for secret patterns by default. A token printed in a log is effectively invisible to automated tools unless a custom script is written to scan them.

Ephemeral CI logs are rarely audited because they are considered transient. Most teams set a retention period of 30 to 90 days and then delete them. But an attacker who monitors logs in real time can capture secrets before deletion. The maintainer in this case found the leak only because they were manually inspecting a failed job—a practice that is not scalable.

There is no standard for token expiration in CI environment variables. Many projects set tokens to never expire, or they use long-lived tokens rotated annually. Short-lived tokens—valid for hours or minutes—are technically feasible but require infrastructure to issue and refresh them. Most CI platforms do not natively support this; they rely on static secrets stored in repository settings.

Open-source projects lack the budget for commercial scanners that cover CI logs. Tools like GitGuardian or TruffleHog offer CI log scanning in their enterprise tiers, but the free versions focus on git history. The result is a blind spot that attackers are increasingly exploiting. A 2025 analysis by a security research group found that 12% of sampled open-source projects had at least one secret exposed in CI logs over a six-month period.

Fixing the Pipeline: Practical Steps for Teams

The first fix is to enforce mandatory pull request review for CI configuration changes. This is a low-cost policy change: configure branch protection rules to require at least one approval for any file under .github/ or ci/. The maintainer's project now does this, but it took a near-miss to implement it.

Short-lived tokens are the second line of defense. Instead of storing a static token in repository secrets, teams can use OpenID Connect (OIDC) to issue tokens that are valid only for the duration of a single job. GitHub Actions supports OIDC for cloud providers like AWS and Azure, and the setup takes a few hours. The token in the leaked PR was a static token; if OIDC had been used, the exposure window would have been minutes, not months.

Automated CI log auditing is another step. Teams can write a simple script that runs after each job and scans the log for patterns matching known secret formats. Open-source tools like trufflehog can be integrated as a post-job step. The script can fail the job if a secret is detected, preventing the log from being stored. This approach is not foolproof—attackers can obfuscate secrets—but it catches the low-hanging fruit.

Token rotation policies should be tied to merges to the main branch, not to a calendar. Every time a change is merged, the token should be rotated. This limits the damage from any single exposure. The practice is common in high-security environments but rare in open source due to the operational overhead of updating secrets across multiple services.

Adopting the OpenSSF Scorecard is a broader step. The Scorecard checks for practices like branch protection, token permissions, and dependency updates. It is free and runs as a GitHub Action. The maintainer's project now runs it weekly, and it flags any workflow that uses a token without OIDC. The Scorecard is not a silver bullet, but it raises the baseline.

A Second Case Study: The Python Package Registry Leak

To illustrate how pervasive these issues are, consider a similar incident from early 2025 involving a popular Python data processing library. In that case, a contributor accidentally committed a file containing a PyPI API token to the repository's .github/workflows directory. The token was not flagged by GitHub's secret scanning because the file extension was .yaml, which is not scanned by default. The token was exposed for six months before a security researcher discovered it during a routine audit of public repositories. The researcher reported the leak privately, and the maintainers revoked the token within hours. However, during that six-month window, the token could have been used to publish malicious releases to PyPI, affecting any project that depended on the library. The library had over 10 million weekly downloads on PyPI.

This second case shares the same root causes: lack of automated scanning for non-standard file types, over-scoped tokens with write access to the package registry, and insufficient oversight of CI configuration changes. The maintainers had not enforced branch protection rules for the .github directory, and the token was a long-lived personal access token with the write:packages scope. After the incident, they implemented OIDC-based authentication for PyPI uploads and added a pre-commit hook to detect secrets in YAML files. These fixes were straightforward but required dedicated effort—effort that many projects cannot spare.

The Unmerged PR as a Warning

That maintainer's unmerged PR is now a case study in conference talks and blog posts. It has been cited in at least two security advisories as an example of how supply-chain vulnerabilities originate not from sophisticated attacks but from mundane neglect. The PR itself was eventually closed, but the underlying issues—unreviewed changes, over-scoped tokens, absent log scanning—remain widespread.

The industry is slowly adopting pre-merge CI scanning. GitHub introduced secret scanning for Actions logs in beta in early 2026, but adoption is low. Most teams do not enable it because it requires a GitHub Advanced Security license and generates noise. The balance between false positives and true leaks is still being tuned.

But most projects still rely on unpaid vigilance. Open-source maintainers are expected to catch leaks in their spare time, without training or tooling. The token leak described here was a lucky catch—a maintainer noticed something odd. The next eight-month leak is almost certainly already active, sitting in a forgotten PR or a stale branch, waiting for someone to look.

So what can you do, starting tomorrow? First, audit your own CI logs. Check the last 90 days of logs for any environment variable that appears in plaintext. Second, enforce branch protection for CI configuration files. Third, adopt OIDC for any token that grants write access to a package registry or cloud provider. Fourth, run a tool like the OpenSSF Scorecard on your repository. These steps are not expensive, and they do not require a dedicated security team. They require only the discipline to treat CI configuration as production code—and the humility to assume a leak is already there.

Recommend Posts
Tech

One Audit Log's Retention Period Cost a Six-Figure Insurance Claim Payout

By Yusuke Tanaka/Jul 17, 2026

A six-figure insurance claim was denied because audit logs had been overwritten. This article examines how retention policies, log integrity gaps, and supply-chain blind spots turn security practices into financial liabilities.
Tech

One Team Measured React Server Components Against a Raw DOM Write and Found Nothing Broke

By Lucas Mendes/Jul 17, 2026

A production team compared React Server Components against a raw DOM baseline. Two weeks, 1.2 million sessions, and no regressions. Here's what they learned.
Tech

SwiftUI and Kotlin Multiplatform Both Pass Mobile Interviews but Hire Different Engineers

By Lucas Mendes/Jul 17, 2026

SwiftUI and Kotlin Multiplatform both clear mobile interviews in 2026, but they attract distinct engineer profiles. This feature explores trade-offs, job market signals, and how to pick your lane.
Tech

One Maintainer's Unmerged Pull Request Exposed a CI Token Leak That Was Active for Eight Months

By Deepa Iyer/Jul 17, 2026

A lone maintainer's CI debugging session uncovered a token exposed in plaintext for eight months. The unmerged PR reveals systemic gaps in supply-chain security.
Tech

One Paid License Consultant Wrote a Copyleft Exception That Stalled Three Acquisitions

By Sara Park/Jul 17, 2026

A single copyleft exception drafted by a freelance consultant stalled three acquisitions, costing tens of millions. How one bad clause became a poison pill.
Tech

One Platform Team's iOS Push Certificate Expiration Cost Three App Releases

By Lucas Mendes/Jul 17, 2026

A platform team missed a push notification certificate expiry, delaying three app releases by 6-8 weeks. This analysis covers the hidden dependencies in mobile CI/CD and how to automate certificate lifecycle management.
Tech

Flutter's Widget Tree vs SwiftUI's View Body Two Teams Paid for Both

By Deepa Iyer/Jul 17, 2026

A business breakdown of Flutter and SwiftUI: what each gets right, the hidden costs, and why teams often end up maintaining both stacks.
Tech

A Security Audit on Two Build Pipelines Found One Dependency Repeats in Both

By Deepa Iyer/Jul 17, 2026

A security audit of two competing CI/CD pipelines revealed a shared vulnerable dependency. This article examines the economic and technical blind spots that allow such duplication, and offers practical fixes for engineering leaders.
Tech

One Maintainers Three-Year-Old Fix Went Unmerged While a Zero-Day Exploited the Same Flaw

By Deepa Iyer/Jul 17, 2026

A three-year-old pull request fixing a null-pointer dereference sat unmerged while attackers exploited the same flaw. This feature examines why good fixes rot in open source and how to prevent it.
Tech

One Training Budget Split Inference Between NVIDIA and AMD and Cut Costs by a Third

By Sara Park/Jul 17, 2026

Splitting inference across NVIDIA and AMD GPUs can cut costs by a third. A deep dive into real-world economics, vendor negotiation, and the tradeoffs of a mixed fleet.
Tech

React Server Components and HTMX Both Offer Less JS But One Team Quit

By Lucas Mendes/Jul 17, 2026

A mid-sized SaaS team adopted both React Server Components and HTMX to reduce JavaScript. Half the engineers quit within six months. Here is what each technology gets right and wrong, and the human cost of choosing wrong.
Tech

Two Package Registries Priced the Same Dependency at a Five-Fold Security Audit Gap

By Sara Park/Jul 17, 2026

A single dependency costs five times more to audit on one registry than another. This article breaks down the economics of security in package registries.
Tech

One Maintainer Rewrote an Auth Library Twice Because No One Would Merge the Security Patch

By Sara Park/Jul 17, 2026

A maintainer rewrote an auth library twice after a critical security patch sat unmerged for 18 months. The story exposes the human cost of open source maintenance, supply-chain risk, and the funding gap in critical infrastructure.
Tech

SwiftUI and Jetpack Compose Share One Syntax But Two Team Cultures

By Deepa Iyer/Jul 17, 2026

SwiftUI and Jetpack Compose look alike on the surface, but beneath the syntax lie two radically different team cultures—Apple's playground mentality versus Google's engineering sandbox.
Tech

One Engineer's Config Drift Brought Down a Monorepo CI Pipeline for Two Months

By Deepa Iyer/Jul 17, 2026

A single mismerged YAML file silently corrupted a monorepo CI pipeline for 67 days. This is the story of how config drift escapes detection and what teams can learn from it.
Tech

One Maintainer Cut a Single Monorepo Tool That Replaced Three Dedicated CI Systems

By Yusuke Tanaka/Jul 17, 2026

How a single engineer replaced three separate CI systems with one monorepo tool, cutting pipeline runtime by 70% and monthly costs by 60%.
Tech

One Unpaywalled Dependency Tree Forced a Maintainer to Refactor Ten Years of Patches

By Deepa Iyer/Jul 17, 2026

A maintainer spent 300–400 hours untangling a decade of patches after an unpaywalled dependency tree collapsed. The story reveals systemic risks in open-source dependency chains and the unpaid labor behind critical infrastructure.
Tech

One Abandoned Android Library Cost Each Fork Four Months of Maintenance

By Yusuke Tanaka/Jul 17, 2026

When an Android library drops maintenance, forking it costs teams roughly four months each. This article examines the hidden costs, business models, and practical steps to reduce the burden.
Tech

One Inference Engineer's GPU Swarm Saved a Week per Pipeline Run

By Deepa Iyer/Jul 17, 2026

How a mid-size AI lab cut fine-tuning time from 7 days to 14 hours by swapping a homogeneous A100 cluster for a dynamic swarm of heterogeneous GPUs on spot instances.
Tech

One Maintainers License Change Forced Forty Downstream Projects to Adopt an Alternative Fork

By Yusuke Tanaka/Jul 17, 2026

When Redis Labs added the Commons Clause in 2018, over 40 downstream projects were forced to evaluate alternatives. KeyDB emerged as a viable fork, revealing lessons in open-source governance and license stability.