ci: pass branch refs through env instead of interpolating into run - #15562
ci: pass branch refs through env instead of interpolating into run#15562christian-byrne wants to merge 1 commit into
Conversation
Three workflow steps interpolate a branch ref directly into a shell command. A ref is attacker-shaped: git allows $, backtick, ;, |, & and parentheses in branch names, so the value lands in the shell as code. All three jobs check out with PR_GH_TOKEN. This is the pattern the repo already uses everywhere else — seven other workflows pass refs as BRANCH_NAME / HEAD_REF / PR_HEAD_REF / TARGET_BRANCH via env. These three were missed rather than exempted. Also adds -- before the ref so a branch named like an option cannot be parsed as one. Reachability is limited: i18n-update-core requires head.repo.full_name == github.repository and a version-bump-* head, so it needs push access already. Defense in depth, not a remote hole.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 37 minutes Limit details: You’ve used the included review currently available. Your 90 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Comment |
🎭 Playwright: ✅ 1841 passed, 0 failed📊 Browser Reports
📦 Bundle: 9.13 MB gzip ⚪ 0 BDetailsSummary
Category Glance App Entry Points — 3.71 kB (baseline 3.71 kB) • ⚪ 0 BMain entry bundles and manifests Status: 1 unchanged Graph Workspace — 1.37 MB (baseline 1.37 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration Status: 3 unchanged Views & Navigation — 124 kB (baseline 124 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces Status: 17 unchanged Panels & Settings — 566 kB (baseline 566 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens Status: 26 unchanged User & Accounts — 27.5 kB (baseline 27.5 kB) • ⚪ 0 BAuthentication, profile, and account management bundles Status: 11 unchanged Editors & Dialogs — 125 kB (baseline 125 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors Status: 8 unchanged UI Components — 67.1 kB (baseline 67.1 kB) • ⚪ 0 BReusable component library chunks Status: 14 unchanged Data & Services — 3.53 MB (baseline 3.53 MB) • ⚪ 0 BStores, services, APIs, and repositories Status: 17 unchanged Utilities & Hooks — 549 kB (baseline 549 kB) • ⚪ 0 BHelpers, composables, and utility bundles Status: 37 unchanged Vendor & Third-Party — 18.1 MB (baseline 18.1 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 18 unchanged Other — 14.2 MB (baseline 14.2 MB) • ⚪ 0 BBundles that do not match a named category Status: 288 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-08-21T14:34:03.500Z",
"gitSha": "cbe07baf9e1af4ea5d166924367fa01c447ae058",
"branch": "cb__workflow-ref-injection-hardening",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2071.573000000001,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.669000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 569.92,
"heapDeltaBytes": 19512372,
"heapUsedBytes": 81496472,
"domNodes": -283,
"jsHeapTotalBytes": 4710400,
"scriptDurationMs": 10.429999999999998,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-idle",
"durationMs": 2074.128999999971,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.316000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 507.73400000000004,
"heapDeltaBytes": 19513736,
"heapUsedBytes": 80649016,
"domNodes": -281,
"jsHeapTotalBytes": 4972544,
"scriptDurationMs": 7.213000000000001,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2136.8640000000028,
"styleRecalcs": 77,
"styleRecalcDurationMs": 50.43500000000001,
"layouts": 12,
"layoutDurationMs": 4.165,
"taskDurationMs": 1101.4489999999998,
"heapDeltaBytes": -2490656,
"heapUsedBytes": 59623480,
"domNodes": -281,
"jsHeapTotalBytes": 4448256,
"scriptDurationMs": 131.28799999999998,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1914.8830000000316,
"styleRecalcs": 74,
"styleRecalcDurationMs": 38.499,
"layouts": 12,
"layoutDurationMs": 3.4420000000000006,
"taskDurationMs": 948.5400000000001,
"heapDeltaBytes": 18042792,
"heapUsedBytes": 80200704,
"domNodes": -280,
"jsHeapTotalBytes": 5496832,
"scriptDurationMs": 127.97500000000001,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1677.204999999958,
"styleRecalcs": 32,
"styleRecalcDurationMs": 17.587000000000003,
"layouts": 6,
"layoutDurationMs": 0.673,
"taskDurationMs": 368.50600000000003,
"heapDeltaBytes": 2971856,
"heapUsedBytes": 65720864,
"domNodes": 78,
"jsHeapTotalBytes": 4456448,
"scriptDurationMs": 9.799000000000001,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1718.2520000000068,
"styleRecalcs": 31,
"styleRecalcDurationMs": 17.782999999999998,
"layouts": 6,
"layoutDurationMs": 0.5630000000000002,
"taskDurationMs": 378.14,
"heapDeltaBytes": 3264984,
"heapUsedBytes": 65961472,
"domNodes": 75,
"jsHeapTotalBytes": 4456448,
"scriptDurationMs": 10.937000000000003,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 590.1230000000055,
"styleRecalcs": 11,
"styleRecalcDurationMs": 7.624999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 376.64799999999997,
"heapDeltaBytes": 10833096,
"heapUsedBytes": 73581556,
"domNodes": 18,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 60.299,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 593.729000000053,
"styleRecalcs": 10,
"styleRecalcDurationMs": 7.042000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 389.122,
"heapDeltaBytes": 10786048,
"heapUsedBytes": 73353488,
"domNodes": 16,
"jsHeapTotalBytes": 5767168,
"scriptDurationMs": 57.584999999999994,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-idle",
"durationMs": 2096.355000000017,
"styleRecalcs": 8,
"styleRecalcDurationMs": 8.167,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 764.3660000000001,
"heapDeltaBytes": -963536,
"heapUsedBytes": 75508440,
"domNodes": -272,
"jsHeapTotalBytes": -1314816,
"scriptDurationMs": 18.719000000000005,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2056.942999999933,
"styleRecalcs": 8,
"styleRecalcDurationMs": 8.327000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 649.1280000000002,
"heapDeltaBytes": -2784892,
"heapUsedBytes": 74183968,
"domNodes": -274,
"jsHeapTotalBytes": -1576960,
"scriptDurationMs": 17.318000000000005,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2246.7229999999745,
"styleRecalcs": 67,
"styleRecalcDurationMs": 13.246,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1323.1950000000002,
"heapDeltaBytes": -7373304,
"heapUsedBytes": 70221676,
"domNodes": -282,
"jsHeapTotalBytes": 483328,
"scriptDurationMs": 373.799,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2761.6219999999885,
"styleRecalcs": 67,
"styleRecalcDurationMs": 15.270999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1693.847,
"heapDeltaBytes": -7776848,
"heapUsedBytes": 69972640,
"domNodes": -278,
"jsHeapTotalBytes": -40960,
"scriptDurationMs": 497.762,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3298.3839999999987,
"styleRecalcs": 64,
"styleRecalcDurationMs": 14.968000000000002,
"layouts": 60,
"layoutDurationMs": 7.964,
"taskDurationMs": 1477.3939999999998,
"heapDeltaBytes": -7791296,
"heapUsedBytes": 71163352,
"domNodes": -289,
"jsHeapTotalBytes": 5500928,
"scriptDurationMs": 413.619,
"eventListeners": -155,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3447.689999999966,
"styleRecalcs": 65,
"styleRecalcDurationMs": 15.677,
"layouts": 60,
"layoutDurationMs": 7.779,
"taskDurationMs": 1476.657,
"heapDeltaBytes": 1526076,
"heapUsedBytes": 80791108,
"domNodes": -287,
"jsHeapTotalBytes": 4714496,
"scriptDurationMs": 413.40500000000003,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "legacy-node-drag",
"durationMs": 2487.072000000012,
"styleRecalcs": 45,
"styleRecalcDurationMs": 9.693999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1502.804,
"heapDeltaBytes": 11146860,
"heapUsedBytes": 96100276,
"domNodes": 10,
"jsHeapTotalBytes": 9105408,
"scriptDurationMs": 477.358,
"eventListeners": 186,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "legacy-node-drag",
"durationMs": 2434.6859999999424,
"styleRecalcs": 45,
"styleRecalcDurationMs": 9.032000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1512.766,
"heapDeltaBytes": -15316556,
"heapUsedBytes": 69814776,
"domNodes": 10,
"jsHeapTotalBytes": 9211904,
"scriptDurationMs": 476.35499999999996,
"eventListeners": 186,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "minimap-idle",
"durationMs": 2011.5200000000186,
"styleRecalcs": 8,
"styleRecalcDurationMs": 6.706,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 596.1840000000001,
"heapDeltaBytes": -13880124,
"heapUsedBytes": 63404868,
"domNodes": -282,
"jsHeapTotalBytes": 3141632,
"scriptDurationMs": 14.445,
"eventListeners": -181,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "minimap-idle",
"durationMs": 2025.131999999985,
"styleRecalcs": 7,
"styleRecalcDurationMs": 7.023999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 692.571,
"heapDeltaBytes": -12089076,
"heapUsedBytes": 71091584,
"domNodes": -283,
"jsHeapTotalBytes": 6287360,
"scriptDurationMs": 18.523,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 582.4520000000462,
"styleRecalcs": 45,
"styleRecalcDurationMs": 9.775,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 391.16200000000003,
"heapDeltaBytes": 10741384,
"heapUsedBytes": 72379088,
"domNodes": 16,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 118.43900000000001,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 575.0789999999597,
"styleRecalcs": 46,
"styleRecalcDurationMs": 9.617,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 395.41700000000003,
"heapDeltaBytes": 11490940,
"heapUsedBytes": 74086080,
"domNodes": 18,
"jsHeapTotalBytes": 6291456,
"scriptDurationMs": 116.01299999999999,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-idle",
"durationMs": 2021.3210000000004,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.710000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 561.482,
"heapDeltaBytes": 313144,
"heapUsedBytes": 62944064,
"domNodes": -282,
"jsHeapTotalBytes": 3923968,
"scriptDurationMs": 9.161000000000003,
"eventListeners": -181,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2022.6020000000062,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.563000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 496.693,
"heapDeltaBytes": 5240044,
"heapUsedBytes": 67745072,
"domNodes": -283,
"jsHeapTotalBytes": 4710400,
"scriptDurationMs": 6.543,
"eventListeners": -181,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1724.6379999999704,
"styleRecalcs": 75,
"styleRecalcDurationMs": 38.599999999999994,
"layouts": 16,
"layoutDurationMs": 4.665000000000001,
"taskDurationMs": 845.187,
"heapDeltaBytes": 18221880,
"heapUsedBytes": 80263952,
"domNodes": -282,
"jsHeapTotalBytes": 4972544,
"scriptDurationMs": 90.75,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1723.573999999985,
"styleRecalcs": 75,
"styleRecalcDurationMs": 36.984,
"layouts": 16,
"layoutDurationMs": 4.848,
"taskDurationMs": 831.424,
"heapDeltaBytes": -4654308,
"heapUsedBytes": 57461620,
"domNodes": -283,
"jsHeapTotalBytes": 4972544,
"scriptDurationMs": 90.397,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-transition-enter",
"durationMs": 1382.1689999999762,
"styleRecalcs": 18,
"styleRecalcDurationMs": 31.158000000000005,
"layouts": 13,
"layoutDurationMs": 13.738999999999997,
"taskDurationMs": 922.5419999999999,
"heapDeltaBytes": -387300,
"heapUsedBytes": 97465976,
"domNodes": 13673,
"jsHeapTotalBytes": 11796480,
"scriptDurationMs": 15.968999999999998,
"eventListeners": 2373,
"totalBlockingTimeMs": 143,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 8612.852000000032,
"styleRecalcs": 251,
"styleRecalcDurationMs": 39.529999999999994,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4601.245,
"heapDeltaBytes": 2376852,
"heapUsedBytes": 79216224,
"domNodes": -278,
"jsHeapTotalBytes": -40960,
"scriptDurationMs": 1114.792,
"eventListeners": -135,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8491.809000000103,
"styleRecalcs": 249,
"styleRecalcDurationMs": 38.40200000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4410.214000000001,
"heapDeltaBytes": -11184012,
"heapUsedBytes": 64667272,
"domNodes": -283,
"jsHeapTotalBytes": 4976640,
"scriptDurationMs": 1076.047,
"eventListeners": -165,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17461.840999999993,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 16660.676,
"heapDeltaBytes": -35320944,
"heapUsedBytes": 177589756,
"domNodes": -8312,
"jsHeapTotalBytes": -15769600,
"scriptDurationMs": 117.034,
"eventListeners": -16389,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17130.564999999933,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 16455.562,
"heapDeltaBytes": -50226616,
"heapUsedBytes": 181203968,
"domNodes": -8312,
"jsHeapTotalBytes": -15495168,
"scriptDurationMs": 106.97200000000001,
"eventListeners": -16391,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 20924.15299999999,
"styleRecalcs": 172,
"styleRecalcDurationMs": 18.859000000000016,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20404.101,
"heapDeltaBytes": -16710536,
"heapUsedBytes": 195455424,
"domNodes": -8312,
"jsHeapTotalBytes": -17412096,
"scriptDurationMs": 470.09899999999993,
"eventListeners": -16383,
"totalBlockingTimeMs": 118,
"frameDurationMs": 17.780000000000047,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 20800.31799999995,
"styleRecalcs": 172,
"styleRecalcDurationMs": 17.951000000000022,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20212.670000000002,
"heapDeltaBytes": -16883344,
"heapUsedBytes": 195300760,
"domNodes": -8312,
"jsHeapTotalBytes": -17674240,
"scriptDurationMs": 473.422,
"eventListeners": -16385,
"totalBlockingTimeMs": 107,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "workflow-execution",
"durationMs": 466.5949999999839,
"styleRecalcs": 20,
"styleRecalcDurationMs": 22.634999999999998,
"layouts": 3,
"layoutDurationMs": 1.175,
"taskDurationMs": 109.988,
"heapDeltaBytes": 5073836,
"heapUsedBytes": 67634536,
"domNodes": 152,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 7.315999999999998,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 458.4669999999278,
"styleRecalcs": 14,
"styleRecalcDurationMs": 22.475,
"layouts": 3,
"layoutDurationMs": 1.23,
"taskDurationMs": 113.979,
"heapDeltaBytes": 4934448,
"heapUsedBytes": 67025704,
"domNodes": 123,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 8.046,
"eventListeners": 97,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
|
Correcting the reachability claim in the description — I understated it for two of the three files. The description says this needs push access already. That is true of
branch=$(gh pr view ... --json headRefName --jq '.headRefName')the head branch of the pull request, which on a fork PR is chosen entirely by the external contributor. The So the actual sequence needs no repository access:
The privileged-commenter check is doing real work — it stops an outsider from starting the job. It does not make the input trusted, because the input comes from the PR rather than from the comment. Confused deputy: the gate authenticates the trigger, not the data.
That moves those two from "defense in depth" to something worth prioritising. It does not change this diff — the Context: this was flagged during review of #14352 with an offer to open a standalone issue, and the offer was accepted (comment). No issue was ever opened and neither file has changed on Deliberately not including a payload here. The character classes |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #15562 +/- ##
==========================================
+ Coverage 78.85% 81.26% +2.41%
==========================================
Files 2214 1887 -327
Lines 119226 114323 -4903
Branches 37220 36517 -703
==========================================
- Hits 94012 92903 -1109
+ Misses 24671 20976 -3695
+ Partials 543 444 -99
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
Three workflow steps interpolate a branch ref directly into a shell command:
i18n-update-core.yamlgithub.head_refpr-update-playwright-expectations.yamlneeds.setup.outputs.branchpr-update-website-screenshots.yamlsteps.pr-info.outputs.branchA branch name is attacker-shaped.
git check-ref-formatrejects spaces,~,^,:,?,*,[and\— but it permits$, backtick,;,|,&and parentheses, and${IFS}covers the lack of spaces. So the ref reaches the shell as code rather than as an argument. All three jobs check out withPR_GH_TOKEN.Not a new idea — the repo already does this correctly
Seven other workflows already pass refs through
envand quote them:ci-tests-e2e.yaml:443,ci-tests-storybook.yaml:175,ci-vercel-website-preview.yaml:82,ci-website-e2e.yaml:86,cloud-dispatch-build.yaml:49,cloud-release-version-bump.yaml:104,release-version-bump.yaml:172.These three were missed, not exempted. This PR applies the existing convention to the remaining sites — it introduces no new pattern to learn.
Reachability, stated honestly
i18n-update-coregates ongithub.event.pull_request.head.repo.full_name == github.repository && startsWith(github.head_ref, 'version-bump-'), so a fork PR cannot reach it — an attacker needs push access to the repo already. That makes this defense in depth and privilege escalation, not a remote hole. Worth fixing because the token these jobs hold is more privileged than the access needed to trigger them, but not worth an incident.Change
env:+ quoted expansion, matching the existing convention, plus--before the ref so a branch named like an option cannot be parsed as one.Verified: all three files parse as YAML, and every
$TARGET_BRANCH/$HEAD_REFuse resolves to a variable defined in that same step'senvblock. No remaining${{ }}interpolation inside anygit push/fetch/checkoutin these files.Behaviour is unchanged for every legal branch name.