Trophy case¶
Real bugs, found by running vlotpipe against real, actively-maintained
pipelines — not synthetic testdata/ fixtures — and verified against
the actual source before being called a bug at all. Every fix below
shipped with a regression test named in this doc, so the specific
real-world shape that broke it can't silently regress.
Every entry below only exists because it was verified as a real bug — not a hypothetical, not "this looked interesting," and not a case where the tool's own judgment merely got confirmed rather than corrected. That distinction matters enough to keep this page to bugs only.
Managed cloud runners flagged as self-hosted (SEC010)¶
Found vetting: astral-sh/ruff 16 false positives, one run.
Every SEC010 hit was a runs-on: label like depot-ubuntu-24.04-4 or
codspeed-macro — third-party runner-as-a-service providers
(Depot, CodSpeed) offering
ephemeral, provider-managed cloud VMs. The rule only recognized GitHub's
own ubuntu-/windows-/macos- hosted prefixes, so a reputable managed
service with an isolation model much closer to GitHub-hosted than to a
genuine self-hosted box got flagged identically to one.
Fix: a managedRunnerPrefixes list (depot-, buildjet-, warp-,
codspeed, namespace-, blacksmith-, ubicloud-) in
internal/rules/baseline/triggers.go. Regression test: "SEC010 does not
fire on a third-party managed runner service."
An explicit, deliberate persist-credentials: true flagged as a mistake (SEC006)¶
Found vetting: astral-sh/ruff 5 false positives.
All 5 hits were jobs that explicitly wrote persist-credentials:
true — deliberate opt-ins for jobs that push commits (a docs deploy, a
typeshed sync). The rule only special-cased the false value; an
explicit, documented true was treated identically to the silent
default it exists to catch.
Fix: internal/rules/baseline/hygiene.go now skips whenever
persist-credentials is set at all, either value — only flags when the
key is absent. Regression test: "SEC006 does not fire on an explicit,
deliberate persist-credentials: true."
issue_comment missing from the dangerous-trigger list (SEC003)¶
Found vetting: vitejs/vite
vite's bot automation includes a ChatOps-style workflow triggered by
issue_comment that checks out a PR head based on the comment — exactly
the privilege-escalation shape SEC003 exists to catch (an
attacker-invokable trigger with real GITHUB_TOKEN scope, checking out
untrusted code) — but issue_comment wasn't in the rule's trigger list
at all, so it silently passed.
Fix: added issue_comment to the dangerous-trigger set in
internal/rules/baseline/triggers.go.
Nested conditional insertion not flattened to real jobs (Azure parser)¶
Found vetting: dotnet/roslyn (Azure Pipelines, 548 lines)
Azure YAML's ${{ if }}: conditional-insertion syntax can nest, and
jobs declared inside a nested conditional block weren't being flattened
into the parsed job list at all — they silently vanished from every
rule's view, rather than erroring or producing a wrong finding.
Fix: internal/parser/azure/azure.go's conditional-insertion
handling now recurses. Regression tests:
TestParseConditionalInsertionIsFlattenedNotTreatedAsAJob,
TestParseNestedConditionalInsertionFlattensToRealJobs.
Azure task:-based scripts invisible to every step.Run-keyed rule (SEC016 + parser)¶
Found vetting: AvaloniaUI/Avalonia (Azure Pipelines, 31k+ stars)
Two jobs ran printenv — dumping the full CI environment, including
whatever secrets Azure injects as env vars, into the build log. First
run against this exact file found zero hits, which turned out to be
the actual bug: Avalonia writes these as task: CmdLine@2 with the
script in inputs.script, not the script:/bash: shorthand that
populates step.Run — the form the brand-new SEC016 rule (built for
exactly this class of finding, see below) checked.
The deeper fix wasn't at the rule level: PERF001 and LEAN001 are
both dual-platform and both keyed entirely off step.Run to detect
dependency-install commands, so both had the identical blind spot on
any Azure pipeline using task: CmdLine@2/Bash@3 instead of the
shorthand — a second bug found by reasoning about what else reads
step.Run, not by a second wrong answer observed live.
Fix: pulled upstream into the parser —
internal/parser/azure/azure.go's task: case now populates
step.Run itself whenever inputs.script/inputs.inlineScript is
present, so every rule keyed off step.Run gets task-based scripts for
free, with no per-rule special case. Regression tests:
TestEnvironmentDumpFiresOnAzureTaskInlineScript,
TestParseTaskInlineScriptPopulatesRun.
A rule born from a real gap, not a hypothetical (SEC016)¶
Found vetting: AvaloniaUI/Avalonia
Before this run, vlotpipe had no rule for a bare printenv/env
dumping the whole CI environment (including injected secrets) to the
build log — the same class of problem as SEC008
(toJSON(secrets)), but expressed as a plain shell command instead of
a GitHub Actions expression, so it needed its own detection. Built
directly from this finding: SEC016
(environment-dump), dual-platform, deliberately excluding safe
single-variable forms (printenv HOME, env FOO=bar some-command).