PolinRider: A Supply-Chain Loader in 40,136 GitHub Repositories
Pinned-commit proof, hidden loaders, propagation and the blockchain-based payload chain.
Cristian Chiriac
- Published:
- 2 November 2026
- Version:
- 1.0
- Last observed:
- 30 October 2026
- Dataset frozen:
- 1 November 2026
- Collection cut-off:
- 31 October 2026, 17:59 UTC
- Tracked items rechecked:
- 1 November 2026, 18:23 UTC
- Time zone
- All dates UTC.
Contents
PolinRider loaders are present in 40,136 public repositories at pinned default-branch commits.
The research in 30 seconds
- What I found
- PolinRider loaders are present in 40,136 public repositories at pinned default-branch commits.
- What this adds
- The owner-wide expansion documents scale beyond the largest public count found in the reviewed sources, together with rewritten-history and pull-request evidence.
- Verified scope
- 40,136 repositories under 3,334 accounts on 30–31 October; default branches form the counting boundary.
- What remains unknown
- Code presence does not establish execution. Shared owners or infrastructure do not independently establish an operator.
The numbers, with their boundaries
Current count
40,136
Proven repositories
30–31 Oct 2026 · UTC
- Counts:
- Unique repository ids passing the fixed code and task-target rules; 3,334 owners.
- De-duplicated by:
- Unique GitHub repository id
- Excludes:
- Repositories whose task points at an empty file (806 on 30 October 2026)
Earlier snapshot or subset
7,332
Active first-pass repositories
29 Oct 2026 · UTC
- Counts:
- Earlier code-search set before owner-wide expansion; not a like-for-like growth measure.
Context · separate measure
806
Empty-target tasks excluded
30 Oct 2026 · UTC
- Counts:
- Repositories whose task target was empty; these cannot execute a target payload and are excluded.
PolinRider is already public. What was missing was its size. The largest public count I found was 1,951 repositories. On 30–31 October 2026, 40,136 public repositories under 3,334 accounts carried the malicious code on their default branch. For each one I recorded the commit, the file and its git object id.
- The count started from 8,219 code-search candidates and grew as I scanned every public repository of each confirmed owner. That round was repeated until it found no new owners.
- Every repository was then proven again at a pinned commit. A random sample of 555 was re-read through a different API, and all 555 matched.
- In 3,281 of the accounts at least one repository was changed in place. In the other 53, the only infected repositories are forks carrying their parent's identical file.
- The code hides in two places. One is a file named like a font that is really JavaScript, started by a hidden VS Code task. The other is a JavaScript payload pushed off-screen by whitespace in a build configuration file.
- Most infections were folded into rewritten, back-dated history and force-pushed in September and October 2026. In 93 of 151 cases I could check, the account that pushed was not the credited author.
- 13 open pull requests carry the payload into other projects.
- The loader fetches its next stage from TRON, Aptos and BNB Smart Chain (BSC). I decrypted 179 of 182 payloads stored on BSC. Most of the addresses involved are already public, some under other campaign names. Two TRON accounts and two command-and-control addresses were not in any public source I checked.
I did not execute anything, contact command-and-control servers, or open victims' data. Public reporting (OpenSourceMalware, Socket) links PolinRider to North Korean operators [1, 2]; I did not make that attribution myself.
Where this stands (1 November 2026)
#The proven set was closed on 1 November 2026 with what had been found up to 31 October 2026, 17:59 UTC; repositories found after that are tracked separately and are not in these figures. The full proof pass at pinned commits ran on 30–31 October. On 1 November 2026, 18:23 UTC a read-only GitHub API recheck covered the 162 repositories, 73 accounts and 12 issues that are tracked one by one (operator repositories, Shai-Hulud accounts, phishing issues), not the whole set.
- Frozen: 40,136 repositories under 3,334 accounts; 3,281 accounts had a repository changed in place.
- Removal, estimated: on 31 October a random sample of 600 proven repositories found 5 cleaned and 2 deleted (about 1%). The full set has not been re-read since 31 October.
- Not counted: 22,870 infected non-default branches; seven fork-collector accounts.
Key findings
#Scope and method
#Expand technical detail · complete record
Full data table · 10 rows
| Data source | What was collected | Scope | Date (UTC) | Coverage limit |
|---|---|---|---|---|
| GitHub code search | 12 queries for task, fake-font and config-payload patterns, sliced by file size | 32,237 hits in 8,219 repositories | 28 Oct 2026 | Default branches only; no forks; identical files de-duplicated |
| Owner-wide expansion | Every public repository of each confirmed owner, repeated for newly found owners until a round found none; forks checked against their parent | 3,457 owners in the final record | 29 Oct 2026 | Seven accounts holding 7,500–89,800 repositories each, all infected ones forks, were recorded but not scanned |
| Proof pass | Default-branch commit, matched file and task target, each by git object id | Every candidate; 39,998 proven (3 added on 31 Oct), then 138 from the 31 Oct extended search | 30–31 Oct 2026 | Default branches; other branches only state-checked |
| GitHub GraphQL object reads | The exact matched file of every candidate, by git object ID, plus the task's target file at the default branch | 8,219 repositories | 29 Oct 2026, before 08:00 | A file deleted from all history cannot be read |
| Fork snapshots | Presence or absence of infection commits in forks taken after the claimed date | 137 repositories with forks | 28 Oct 2026 | Only repositories that have forks |
| GitHub public events | Push and force-push events with their actors | 478 infected repositories | 28 Oct 2026 | About 90 days or 300 events per repository |
| Pull-request search | PRs by the credited authors of infection commits | 5,799 PRs into 790 repositories | 28 Oct 2026 | Authors found through commits only |
| TRON, Aptos, BSC, Ethereum explorers and public RPC | Transactions and memos of the dead-drop accounts | 7 TRON accounts, 1 BSC sender, 1 Ethereum address | 28–29 Oct 2026 | Funder graph capped at 80 recipients each |
| Static decoding | Python re-implementations of each obfuscation and decryption layer, in an isolated virtual machine | 182 BSC payloads, 6 font-variant samples, config variants | 29 Oct 2026 | Nothing executed; 3 payloads not decrypted |
| Registry data (RDAP) and public reporting | Address-space holders; prior publications | All resolved command-and-control addresses | 29 Oct 2026 | Origin AS not checked per prefix |
Decoded payload text never left the virtual machine. Early in this work some of it was printed on my
workstation, and Microsoft Defender quarantined it as Trojan:NPM/PolinRider.DB!MTB, which also confirms
the family. Only counts, hashes, addresses and dates were brought out. Repository owners are treated as
victims and are not named.
How it started
#I found PolinRider while investigating a different campaign, the Contagious Interview fake job tests
described in Contagious Interview. Seventeen repositories carrying that campaign's errorHandler.js loader
also had a VS Code task that ran Node.js on a file named fa-brands-regular.woff2. A real web font is
binary. These files were text.
A first search on 28 October found 832 such repositories under 314 owners. 734 of them were not in OpenSourceMalware's public lists, whose last update was dated 10 July 2026. A wider search the same day returned 32,237 raw hits in 8,219 repositories under 3,060 owners. On 29 October I verified every one.
Code search misses most of the campaign, because it indexes only some repositories and no forks. So I then listed every public repository of each confirmed owner and checked them all, and repeated that for each owner the round turned up. The fourth round found nothing new.
The proof pass: 39,998 repositories
#On 30 October every candidate from both passes was proven again from scratch:
- read the repository by numeric id;
- pin its default-branch commit;
- read the matched file at that commit;
- apply a fixed rule.
On 31 October three more repositories passed the same rule. A wider read of lure and tool repositories
found them, each with the hidden config payload in an ordinary build config (vite.config.js,
postcss.config.js, astro.config.mjs). None is a fork and all three owners are new. They are included in the
table, the chart and the account counts below.
Later on 31 October an extended search added 138 more under the same rule, for 40,136 repositories under 3,334 accounts. I listed every public repository of the owners of newly proven repositories in all activities, and ran 36 code searches scoped by file name and extension. Listing owners found 136 of them; the scoped searches added 2. 122 carry the VS Code task and 16 the config payload. 18 are forks, none an identical copy of its parent, and 11 owners are new. Two more matched but sit in a test-fixture or documentation path, so the dataset rule leaves them out. The verdict table and the chart below describe the 39,998; the account table includes the 138.
A task file counts only if:
- it runs on folder open;
- it starts
nodeon a file that is not a script; - that target exists at the same commit, is not empty and looks like JavaScript.
A config file counts only with the campaign's global marker plus a long whitespace run or a line over 1,500 characters.
Full data table · 10 rows
| Verdict | Repositories | Note |
|---|---|---|
| Proven | 39,998 | Under 3,323 owner accounts; 3 of them added on 31 October |
| …VS Code task + JavaScript disguised as a font | 30,005 | |
| …hidden config payload | 12,355 | 2,362 repositories carry both |
| …forks | 6,866 | 719 of them only carry their parent's identical file |
| Task points at an empty file | 806 | Cannot run code; not counted |
| No evidence at the current commit | 360 | Cleaned or moved; not counted |
| Task target deleted | 131 | Not counted |
| Security datasets and research copies | 78 | Not counted |
| Repository deleted | 25 | Not counted |
| Needs manual review | 3 | Not counted |
Snapshot at a date: the 39,998 repositories proven by the morning of 31 October 2026. The 138 added later that day are not split by form here. Each repository counted once; 2,362 carry both forms.
Table view
| Item | Value | Note |
|---|---|---|
| VS Code task + fake font only | 27,643 | |
| Hidden build-config payload only | 9,993 | |
| Both | 2,362 |
| Accounts | Count | Definition |
|---|---|---|
| Owners with a non-inherited infected repository | 3,281 | At least one proven repository that is not an identical copy of a parent. This shows the file was changed in the owner's own repository; it does not show how the account was compromised |
| Inherited only | 53 | Only forks that carry the parent's identical infected file |
| Dataset only | 75 | Only security datasets; not counted as victims |
| Nothing proven now | 62 | Earlier evidence no longer present |
The sample check re-read 555 proven repositories, stratified by rule and account type, through the REST contents API at the pinned commit. All 555 matched. An earlier sample had found seven task files whose target was empty, so the rule was tightened before the final count. That removed 806 repositories.
22,870 non-default branches in 6,530 repositories also carried the payload on 29 October. They are not added to the repository count.
First pass: code-search candidates (29 October)
#Expand technical detail · complete record
The tables in this section describe the first pass only. Its figures are kept because the later sections analyse that set.
Full data table · 11 rows
| Verdict | Repositories | Accounts | Rule |
|---|---|---|---|
| Candidates from code search | 8,219 | 3,060 | At least one file matching a PolinRider pattern |
| Confirmed malicious | 7,479 | 2,651 | The matched file contains the malicious pattern (91%) |
| …active: VS Code task + fake font | 5,552 | 1,845 | Task runs node on a font-named file that is text |
| …active: hidden config payload | 1,780 | 936 | Marker + long whitespace run or a line over 1,500 characters |
| …task present, target file deleted | 124 | 84 | Malicious, but not runnable as found |
| …task and target both removed later | 23 | 7 | Read from history |
| Still active on the default branch | 7,332 | 2,606 | 249 organizations among the owners |
| Pattern match only | 665 | 423 | Not counted |
| Research or defensive copies | 62 | 49 | Not counted |
| Neutralized (the "font" is a real font) | 10 | 5 | Not counted |
| Deleted or private | 3 | 2 | Not counted |
How each number was produced:
| Number | How I counted it |
|---|---|
| 8,219 / 3,060 | Unique repositories and owners among 32,237 hits for twelve code-search queries. A floor: code search covers default branches only and excludes forks (none of the 8,219 is a fork). |
| 7,479 | The exact file the search matched, fetched by git object ID. A task file counts only if it runs on folder open and starts node on a non-script file. A config file counts only with the campaign's global-variable marker plus a long whitespace run or an over-long line. |
| 7,332 | The same file still at the same path on the default branch, read on 29 October before 08:00 UTC. |
| 5,552 | For each task, the target "font" was read at the default branch: 3,870 begin like JavaScript, 1,663 with a short glob header, 20 are other text. |
| 62 research | A strict path rule: test data, fixtures, documentation, detection rules or scanners. An earlier loose rule matched substrings inside unrelated names and was discarded. |
| 249 organizations | Organization owners among the 7,332 active repositories (255 among the 7,479 confirmed). |
When the infected repositories were last pushed (platform pushedAt, which is the latest push, not
the infection date):
| Last push | Config-payload repositories (1,780) | All 8,219 candidates |
|---|---|---|
| Up to November 2025 | 40 | — |
| December 2025 – August 2026 | 656 | — |
| September 2026 | 221 | 1,314 |
| October 2026 | 863 | 5,888 |
A separate pass on 28 October read 7,569 candidates and found 5,245 still infected then. The 29 October verification superseded it; together the two sets cover 7,739 repositories under 2,712 accounts.
Where the code hides
#1. A VS Code task and a fake font
#- In the tasks I sampled, all used
"runOn": "folderOpen". In 156 of 178 the label was a lint- or build-like name, and the task was hidden from the terminal. - In 138 of 178 the command checks for Node.js on macOS, Linux and Windows and fails silently; 13 call
nodedirectly. The target has a font extension:.woff2,.woff,.ttf,.otf,.eot, and in a few cases.orc. - The "font" sits deep in an unrelated folder, under a
public/fonts/path, so it looks like a bundled asset. Every one of 248 resolved targets in an earlier sample was text.
The task needs the user to open the folder in VS Code and trust the workspace. No dependency install is needed.
2. A payload behind whitespace in a build config
#Obfuscated JavaScript is appended to a configuration file that build tools load automatically:
tailwind.config.js, postcss.config.mjs, and later Next.js and Vite configs. It starts after hundreds
of spaces. In one infected repository, a PostCSS configuration that shows 12 normal lines is 5.4 KB on
disk. The code sets a global marker (_V, later !) so it runs once per process, then starts the loader.
| Config variant (by payload size) | First server-side push | Repositories in the early set |
|---|---|---|
| about 5,087 characters | 20 March 2025 | 1 |
| about 3,300 characters | 7 June 2025 | 10 |
| about 4,111 characters | 18 June 2025 | 8 |
| about 5,009 characters | 2 August 2025 | 1 |
! marker, about 4,782 characters |
22 October 2025 | 2 |
Statically, the config payload has three layers: a character shuffle, a dictionary decoder and a string table. Decoded, it is the same TRON → BSC dead-drop loader described below, with an Aptos fallback. Two early samples still have one layer left.
How the forms changed over time
#- 01Config payload behind whitespaceT1027First confirmed 20 March 2025; still the form of 1,780 active repositories in October 2026
- 02Fake fa-brands-regular.woff2 on some repositoriesT1036.008October – November 2025
- 03VS Code folder-open task + JavaScript disguised as a fontT1204.002Mass scale in 2026 — 897 pushes of infected repositories in September and 4,137 in October
How it spreads
#Rewritten history
#| Measure | Value |
|---|---|
| Infection commits examined | 620 |
| …pushed in September or October 2026 | 620 |
| …claiming an author date before July 2026 | 536 |
| Repositories where a fork snapshot disproves the date | 36 (32 proven, 4 strong) |
| Oldest disproved date | 9 February 2020 |
| Other disproved dates | 25 Jul 2021, 26 Oct 2023, 9 Mar 2024, 3 Jan 2025, 2 Feb 2025, 27 Aug 2025, 9 Jun 2026 |
| Repositories with 2016–2024 infection commits and no fork to test | 62 |
Commit dates in this campaign are attacker-controlled. Only push events, pull-request force-push events, repository creation and fork snapshots date anything.
Who pushed
#Full data table · 11 rows
| Measure | Value |
|---|---|
| Infected repositories whose events were read | 478 |
| …infecting push found | 151 (24 in September, 127 in October 2026) |
| …outside the event window | 205 |
| …no events | 122 |
| Pusher different from the credited author | 93 of 151 |
| Distinct pushing accounts | 99 |
| …long-standing developer accounts (created before mid-2025, 50+ contributions) | 64 |
| …no longer accessible | 22 |
| …new or thin, unclassified | 13 |
| Accounts that infected 3 or more repositories | 13 |
| Accounts that pushed to more than one owner | 6 |
The shape is one account sweeping several repositories of one organization within minutes. One account touched five repositories of three owners in six minutes. Another touched six repositories of one organization in 84 minutes. Two accounts each infected five repositories within the same minute. In one organization, five pull requests credited to one developer were force-pushed within four minutes by a different account with write access.
The 46 operator-side accounts I could identify had no commits or pull requests in anyone else's repositories.
Pull requests
#| Group | PRs | Open | Merged | Closed | How the payload arrived |
|---|---|---|---|---|---|
| Later branch rewrite | 12 | 10 | 0 | 2 | Clean when opened; head force-pushed 6–29 Sep 2026 |
| Present from the start | 14 | 3 | 11 | 0 | Mostly the config form, into small agency and student organizations |
| Total | 26 | 13 | 11 | 2 |
The 12 rewritten pull requests target, among others, a widely used data-privacy SDK (closed unmerged on 9 October), an AI framework's Dart SDK (closed unmerged on 28 October) and open-source hospital software (still open). A broader pass found 296 repositories with merged pull requests touching the abused paths. 125 of them, in 34 organizations, are infected now; for those the route is not proven.
The payload chain
#- 01Loader runsT1059.007Folder-open task runs the fake font, or the build loads the poisoned config
- 02TRON dead dropT1102.001Latest memo of a TRON account = a BSC transaction hash written backwards
- 03Aptos fallbackT1102.001The same pointer read from an Aptos account if TRON fails
- 04BSC transaction inputT1027.013Encrypted next stage written by one sender to the burn address
- 05Decrypt and runShort XOR key; eval in-process and in a detached node -e process
- 06Remote-access toolT1071.001Socket.IO control, command execution, secret-file sweep, clipboard; most builds name an Evoxt address
The font form also uses a fourth lookup: it reads the latest transaction from an Ethereum address to learn the current command-and-control IP address, then fetches the next stage from that server on port 443. That address published eight IP addresses through 609 transactions between 25 July and 19 October 2026.
The mechanism, the first TRON accounts, the earliest Aptos fallbacks and the loader keys are already public [1, 2, 4]. I do not reproduce keys here.
Dead-drop accounts and what they point to
#| TRON dead drop | Payloads in the BSC corpus | Public before this work |
|---|---|---|
TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v |
61 | Yes [8, 9] |
TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatSe |
53 | Yes [7, 10] |
TCqf6ZkaQD84vYsC2cuu1jRwB6JveTaRrF |
27 | Yes [4] |
TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP |
19 | Yes [1] |
TFMryB9m6d4kBMRjEVyFRbqKSV1cV2NcpH |
14 | Yes [4] |
TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG |
7 | Yes [1] |
TPDBqDKAYfRVvVYDNZVxY8CRfovkwDaSgW |
1 (10 Mar 2026) | Not found |
| Total | 182 |
One TRON funder, not found in public sources, paid four of these accounts, including TLmj13 with 53
payloads. That account sent 58 transactions; 57 carry reversed BSC hashes, pointing to 53 distinct payloads from 12 June 2025 to
27 January 2026, none of them among the 128 found through the other accounts.
The BSC corpus
#All 182 distinct payload transactions from the one BSC sender, by block timestamp (UTC). Enumerated 28–29 October 2026.
Table view
| Item | Value | Note |
|---|---|---|
| Jun 25 | 39 | |
| Jul 25 | 4 | |
| Aug 25 | 6 | |
| Sep 25 | 0 | |
| Oct 25 | 10 | |
| Nov 25 | 5 | |
| Dec 25 | 15 | |
| Jan 26 | 11 | |
| Feb 26 | 38 | |
| Mar 26 | 9 | |
| Apr 26 | 0 | |
| May 26 | 18 | |
| Jun 26 | 11 | |
| Jul 26 | 0 | |
| Aug 26 | 0 | |
| Sep 26 | 9 | |
| Oct 26 | 7 |
| Measure | Value |
|---|---|
| Distinct encrypted payloads enumerated | 182 (12 Jun 2025 – 7 Oct 2026) |
| Sender transactions in total (nonce) | about 347; about 165 not enumerated |
| Decrypted with keys taken from loaders | 99 |
| Decrypted with a key recovered by known-plaintext attack | 80 |
| Decrypted in total | 179 (3 failed) |
| Family 1: chained loaders | 86 |
| Family 2: final remote-access/stealer builds | 93 (30–92 KB, June 2025 – March 2026) |
| Final builds with strings recovered | 79 (60,716 of 70,861 strings) |
The 86 loaders use the same three-layer obfuscation and point onward to a TRON account; 48 start a
detached node -e process and 16 use eval. Their three Aptos fallback accounts are all in
public reporting [4, 8, 10]. The 93 final builds are packed with obfuscator.io, and every
one is distinct. Their embedded build tags run from 250602 to 260206; the authors wrote these strings,
so they are not verified dates.
Capabilities present in the 79 builds whose strings were recovered:
| Capability | Builds (of 79) |
|---|---|
| Socket.IO command-and-control channel | 75 |
Command execution through child_process |
74 |
| Home-directory and secret-file sweep | 73 |
| Clipboard access | 34 |
| Telegram channel | 24 |
| Python second stage | 1 |
Public reports already describe similar capabilities [2, 4, 5], so none of this is presented as new. It is read from code, not observed in operation.
Command-and-control addresses
#| Address | Role | Dates | Builds | Public before this work |
|---|---|---|---|---|
136.0.9[.]8 |
Final payload | 17 Jun 2025 – 6 Jan 2026 | 18 | Yes [7, 9, 10] |
166.88.4[.]2 |
Final payload | 17 Jun 2025 – 7 Oct 2025 | 14 | Yes [7, 9, 10] |
23.27.202[.]27 |
Final payload | 20 Jun 2025 – 19 Dec 2025 | 10 | Yes [7, 8, 9, 10] |
198.105.127[.]210 |
One chained loader | 10 Mar 2026 | 1 | Yes [4, 9, 10] |
166.88.134[.]62, 23.27.13[.]135, 166.88.73[.]46, 193.247.144[.]38 |
Ethereum-published | 25 Jul – 19 Oct 2026 | — | Yes [3, 4, 5] |
166.88.134[.]75, 91.218.183[.]174 |
Ethereum-published | same | — | Yes [4] |
23.27.13[.]72, 103.179.142[.]155 |
Ethereum-published | same | — | Not found |
Fifty of the 79 builds whose strings I recovered name no IP address.
Infrastructure: one hosting provider
#| Address block | Holder per registry | Abuse contact |
|---|---|---|
23.27.x, 166.88.x |
Evoxt (UK), assigned within Ace Data Centers ranges (ARIN) | Evoxt, optionally Ace Data Centers |
136.0.9[.]0/24, 166.88.4[.]0/24 |
Evoxt (UK) | Evoxt |
193.247.144.x, 91.218.183.x |
Evoxt Enterprise (RIPE) | Evoxt |
103.179.142.x |
Evoxt Enterprise US (APNIC) | Evoxt |
198.105.127.x |
SYN LTD, assigned to Evoxt (RIPE) | SYN LTD |
Evoxt (AS149440) is a self-service VPS provider based in Kuala Lumpur. It sells plans from about $2.99, accepts cryptocurrency, and asks for identification only from clients it considers suspicious. Its acceptable-use policy bans malware and botnet control. It is not on Spamhaus's ASN drop list. Public reports also tie it to unrelated state-linked actors [6, 7].
My assessment, with moderate-to-high confidence: an abused budget host, not a "bulletproof" one. Four Ethereum-published addresses were public from 17 September 2026 [3], and SafeDep named Evoxt on 30 September [4]. I found no sign that the provider acted; the actor kept rotating between Evoxt addresses.
ATT&CK mapping
#Expand technical detail · complete record
| Technique | Name | Tactic | Evidence |
|---|---|---|---|
| T1195.002 | Compromise Software Supply Chain | Initial Access | Malicious code committed into thousands of legitimate repositories and pull requests |
| T1078 | Valid Accounts | Initial Access | Infections pushed by long-standing developer accounts other than the credited authors (inferred compromise) |
| T1204.002 | Malicious File | Execution | Folder-open task requires the user to open and trust the project |
| T1059.007 | JavaScript | Execution | Loader, chained loaders and final builds are JavaScript run by Node.js |
| T1036.008 | Masquerade File Type | Stealth | JavaScript stored with .woff2, .woff, .ttf, .otf and .eot extensions |
| T1027 | Obfuscated Files or Information | Stealth | Whitespace-hidden config payload; three-layer shuffle obfuscation; obfuscator.io packing |
| T1027.013 | Encrypted/Encoded File | Stealth | XOR-encrypted next stages stored in BSC transaction input |
| T1102.001 | Dead Drop Resolver | Command and Control | TRON memos, Aptos accounts and an Ethereum address point to the next stage or the current server |
| T1071.001 | Web Protocols | Command and Control | Next stage fetched over HTTP on port 443; Socket.IO control channel in final builds |
| T1552.001 | Credentials In Files | Credential Access | Home-directory and secret-file sweep in 73 of 79 builds (read from code) |
| T1115 | Clipboard Data | Collection | Clipboard access in 34 of 79 builds (read from code) |
Evidence register
#Expand technical detail · complete record
One row per proven repository with repository id, owner id, default-branch commit, path, git object id, size, rule and task-target checks, plus a commit permalink; 555-repository independent sample re-read through REST. No file contents stored.
Source: GitHub GraphQL and REST, read from an isolated virtual machine · Collected 30 October 2026
Exact matched objects read by git object ID; per-repository verdict with mechanism, owner type and default-branch state. The list of 7,332 active repositories was provided to GitHub.
Source: GitHub code search and GraphQL object reads · Collected 29 October 2026
Forks created after a claimed infection date that do not contain the infection commit; 36 repositories, oldest disproved date 9 February 2020.
Source: GitHub repository and fork metadata · Collected 28 October 2026
Push events for 478 infected repositories; 151 infecting pushes found; actor differs from credited author in 93.
Source: GitHub public events · Collected 28 October 2026
26 pull requests confirmed to carry the payload, with head-branch force-push events dated 6–29 September 2026 for 12 of them.
Source: GitHub pull-request search and timeline events · Collected 28 October 2026
182 distinct encrypted transaction inputs from one sender, linked from 7 TRON accounts; 179 decrypted by re-implementation in an isolated VM; families, build tags and recovered strings recorded as metadata only.
Source: Public TRON, Aptos and BSC explorers and RPC · Collected 29 October 2026
609 transactions from 25 July to 19 October 2026 publishing eight command-and-control IP addresses.
Source: Public Ethereum explorer · Collected 28 October 2026
RDAP records for every resolved command-and-control address, plus the provider's public terms and reputation data.
Source: ARIN, RIPE and APNIC RDAP; provider website; Spamhaus · Collected 29 October 2026
Confidence and alternative explanations
#| Inference | Confidence | Alternative explanation | Why it is less likely |
|---|---|---|---|
| Pushing accounts are compromised developers | Moderate | The operators own those accounts | 64 have years of unrelated activity; operator-side accounts show none |
| Back-dated commits are deliberate | High | Clock errors on developers' machines | Hundreds of dates, all disproved or pushed in the same two months |
| The final builds are one actor's tooling | Moderate | Several actors share the code | One BSC sender, one funder graph and one hosting provider |
| Evoxt is abused rather than complicit | Moderate–high | A deliberately permissive host | Ordinary terms and pricing; unrelated actors use it; not on drop lists |
| North Korean attribution | Not assessed here | — | Taken from public reporting [1, 2] |
Timeline
#Exact platform and on-chain dates:
Earliest server-confirmed infected repository
Config payload in a Tailwind configuration; repository created and pushed the same day
First encrypted payload written to BSC
First final builds naming 136.0.9[.]8 and 166.88.4[.]2
First push of the "!" marker config variant
Last transaction of the TLmj13 TRON dead drop
OpenSourceMalware publishes its PolinRider dossier
Last final-build transaction found
Socket's 108-package report covered by The Hacker News
Ethereum address begins publishing command-and-control addresses
609 transactions, eight addresses, until 19 October 2026
First pull-request branch force-pushed with the payload
The wave runs until 29 September 2026
Socket publishes the Ethereum dead drop and four addresses
SafeDep names Evoxt and six of the eight Ethereum-published addresses
Last BSC payload transaction found
8,219 candidates verified, 7,332 of them active infections
Proof pass completes at 39,995 repositories under 3,320 accounts
Three more config-payload repositories added, 39,998 under 3,323 accounts
Extended search adds 138 more, 40,136 under 3,334 accounts
Periods that cannot be pinned to a day: config-payload variants appear from June to October 2025; fake
fa-brands-regular.woff2 files appear in October–November 2025; infected repositories received 897
pushes in September 2026 and 4,137 in October 2026.
Data notes and reconciliation
#Expand technical detail · complete record
Full data table · 11 rows
| Item | Values seen | Explanation |
|---|---|---|
| Infected at HEAD before full verification | 5,245 and 5,249 | Two snapshots of the 28 October file-read set; superseded |
| 7,332 vs 39,998 | First pass vs proof pass | 7,332 is the code-search set on 29 October; 39,998 adds the owner-wide expansion and forks |
| 41,369 vs 39,995 | 29 Oct full run vs 30 Oct proof pass | The proof pass removed 806 empty-target tasks and counts repositories by id, so renamed repositories are not counted twice |
| 39,995 vs 39,998 | 30 Oct vs 31 Oct | Three config-payload repositories found by a wider read of lure and tool repositories |
| 39,998 vs 40,136 | 31 Oct, before and after the extended search | 138 repositories, found mostly by listing every repository of newly proven owners |
| Organizations | 249 vs 255 | 249 among active repositories, 255 among all confirmed |
| Capability counts | 75/74/73/34/24 vs 63/62/61/22/17 | Two counting passes; the higher set is the stored per-build metadata and is used here |
| Final command-and-control ports | Not in metadata | Left out of this article |
166.88.134[.]75, 91.218.183[.]174 |
Earlier marked unpublished | Both appear in SafeDep [4]; corrected here |
23.27.13[.]72, 103.179.142[.]155 |
Not found | Rechecked on 2 November 2026 in sources 1–5, 7 and 9–11 (live pages, the text files of the two cited GitHub repositories, and the Internet Archive captures of SafeDep from 27 October and Socket from 24 September): neither appears. Socket [3] and Deep Woods [5] list four Ethereum-published addresses; SafeDep [4] lists those four and the two in the row above. Sources 6 and 8 were not rechecked |
| PolinRider total including pull-request and first-round sets | 7,809 | Derivation not fully documented; not used |
Defensive checks
#- Open unfamiliar projects in restricted mode. VS Code's workspace trust stops folder-open tasks.
Before trusting a folder, read
.vscode/tasks.jsonfor"runOn": "folderOpen". - Check that fonts are fonts. A
.woff2,.woff,.ttf,.otfor.eotfile that opens as text is a strong signal. - Look past the right edge of build configs. Search
tailwind,postcss,nextandviteconfigurations for long whitespace runs, over-long lines andglobal['_V']orglobal['!']. - Do not trust commit dates. Use push events, pull-request force-push events and fork snapshots.
- Re-review pull requests whose head branch was force-pushed after review.
- Treat an infected repository as an infected machine or token of the account that pushed, not only of the credited author.
- Scan all branches. Code search sees only default branches.
- Network: developer machines and CI rarely need to query TRON, Aptos, BSC or Ethereum RPC from
node. Alert on that, and on the addresses below.
- 01
Search every branch for .vscode/tasks.json tasks with runOn: folderOpen that start node on a font-named file.
Data needed: A clone of each repository with all branches; code search sees only default branches.
What a result does not show: A match shows the loader is present, not that it ran.
- 02
Open .woff2, .woff, .ttf, .otf and .eot files as text; a font file that reads as text is a strong signal.
Data needed: Repository files.
What a result does not show: Covers the font-carrier form only; the second form hides in build configuration files.
- 03
Search tailwind, postcss, next and vite configurations for long whitespace runs, over-long lines and global['_V'] or global['!'].
Data needed: Repository files, all branches.
What a result does not show: Matches the forms recorded on this page; the forms changed over time.
- 04
Compare commit dates with push events, pull-request force-push events and fork snapshots.
Data needed: Repository events from GitHub, and a fork or backup to compare against.
What a result does not show: GitHub's event window is limited; for that reason the pusher analysis here covers 151 of 478 repositories.
- 05
Alert when node on developer machines or CI queries TRON, Aptos, BSC or Ethereum RPC, and on the addresses under Indicators.
Data needed: Network or DNS logs from developer machines and CI runners, attributed to the process.
What a result does not show: Such queries are rare from node on these machines, not proof on their own; ports of the final command-and-control servers are not confirmed.
Detection rules
#Written from the inclusion rules above, for source files rather than binaries.
Matches .vscode/tasks.json files with the PolinRider trigger: a folderOpen task whose command runs node on a file with a font, image or made-up extension (.woff2, .ttf, .orc, .lkf and others). Proof additionally requires the target to be a non-empty JavaScript file.
- Status
- experimental
- Family
- PolinRider
- Platforms
- none recorded
- Engines tested
- YARA 4.5.0
- Known benign cases
- none recorded
- Testing
- Rewritten on 2 November: the first version matched none of 199 proven tasks, because it expected node and the target as separate JSON strings and knew only font extensions. The proven tasks run node inside one shell command string, and many target made-up extensions such as .orc. This version looks for node followed by a path with a font, image or made-up extension in any folderOpen task. It matched all 199 files it was written against, all 300 held-out files, and none of 88 benign tasks.json files. The proof pass chose the proven files with a similar check (a folderOpen task running node on a non-JavaScript file), so these runs show that the rule finds the proven set; they do not show that it finds variants without those markers.
Check results
| Date | Engine | Corpus | Result |
|---|---|---|---|
| 2026-11-02 | YARA 4.5.0 | Proven PolinRider .vscode/tasks.json files the rule was written against (199) | 199 of 199 matched |
| 2026-11-02 | YARA 4.5.0 | Proven tasks.json files not used to write the rule, random sample (300) | 300 of 300 matched |
| 2026-11-02 | YARA 4.5.0 | The other proven sets of this investigation (1,194 files) | 0 matches |
| 2026-11-02 | YARA 4.5.0 | Benign source code: shallow clones of next.js, microsoft/vscode and vscode-extension-samples (56,864 files, 88 of them tasks.json) | 0 hits |
| 2026-11-02 | YARA 4.5.0 | Benign files in the analysis VM: npm tools (19,474), Python standard library and packages (29,360), git sample hooks (14) | 0 hits |
rule CMPC_PolinRider_VSCode_Task_Autorun
{
meta:
author = "Cristian Chiriac / CMPC Research"
description = "PolinRider trigger: VS Code folderOpen task that runs node on a file with a font, image or made-up extension"
status = "experimental"
date = "2026-11-02"
scope = "Run on .vscode/tasks.json; confirm the target file is JavaScript before acting"
targets = "woff2 woff ttf otf eot orc lkf lfk llf glb fml svg png jpeg sol: every extension in the proven tasks"
strings:
$open = "folderOpen" ascii
$node = /\bnode(\.exe)?\s+(\\?["'])?(\.{0,2}[\/\\]{1,2})?[\w.\-\/\\\[\]()@]+\.(woff2?|ttf|otf|eot|orc|lkf|lfk|llf|glb|fml|sol|svg|png|jpe?g|gif|ico|bmp|webp)\b/ ascii
condition:
filesize < 200KB and $open and $node
}Matches files that carry the PolinRider loader on one long line: the global['_V'] or global['!'] marker, or an _$_xxxx obfuscator name, followed by at least 300 more characters on the same line. In build configurations the line is usually pushed off-screen by spaces or tabs; the rule does not depend on that padding.
- Status
- experimental
- Family
- PolinRider
- Platforms
- none recorded
- Engines tested
- YARA 4.5.0
- Known benign cases
- none recorded
- Testing
- Rewritten on 2 November: the first version found 8 of 200, because it required files over 20 KB and a 400-character run of spaces, and it hit 13 benign files. This version drops both conditions and requires the marker to be followed by at least 300 characters on the same line. It matched all 200 files it was written against, all 297 held-out files, and no benign file, 1,685 of them configuration files. The proof pass chose the proven files with the same markers plus a long line or a long run of spaces, so these runs show that the rule finds the proven set; they do not show that it finds variants without those markers.
Check results
| Date | Engine | Corpus | Result |
|---|---|---|---|
| 2026-11-02 | YARA 4.5.0 | Proven PolinRider files carrying the appended loader, mostly build configurations (200; the files the rule was written against) | 200 of 200 matched |
| 2026-11-02 | YARA 4.5.0 | Proven files of the same set not used to write the rule, random sample (297; 3 no longer available) | 297 of 297 matched |
| 2026-11-02 | YARA 4.5.0 | The other proven sets of this investigation (1,196 files) | 0 matches |
| 2026-11-02 | YARA 4.5.0 | Benign source code: shallow clones of next.js, microsoft/vscode and vscode-extension-samples (56,864 files, 1,673 of them *.config.* files) | 0 hits |
| 2026-11-02 | YARA 4.5.0 | Benign files in the analysis VM: npm tools (19,474), Python standard library and packages (29,360), git sample hooks (14) | 0 hits |
rule CMPC_PolinRider_BuildConfig_Appended_Loader
{
meta:
author = "Cristian Chiriac / CMPC Research"
description = "PolinRider loader appended to a file: global['_V'] / global['!'] or an _$_xxxx name, then the rest of the loader on the same line"
status = "experimental"
date = "2026-11-02"
scope = "Run on *.config.(js|ts|mjs|cjs), postcss/tailwind/vite/next/eslint configurations and font-named files that read as text"
strings:
$g = /global\[\s*['"](_V|!)['"]\s*\][^\n\r]{300}/ ascii
$s = /_\$_[0-9a-f]{4}[^\n\r]{300}/ ascii
condition:
filesize < 5MB and any of them
}If you find it in your repository
#- Remove the task, the fake font and any config payload; check every branch and open pull request.
- Assume the machine of the account that pushed the change is compromised. Rebuild it, then rotate GitHub, npm and cloud tokens, SSH keys and passwords saved in browsers, from a clean device.
- Rewritten history means the bad commit may look old. Compare against a fork or a backup.
Indicators
#Expand technical detail · complete record
| Type | Value | Context | Copy | |
|---|---|---|---|---|
| ip | 136.0.9[.]8 | Final builds, Jun 2025 – Jan 2026; public [7, 9, 10] Provenance: Previously documented | ||
| ip | 166.88.4[.]2 | Final builds, Jun – Oct 2025; public [7, 9, 10] Provenance: Previously documented | ||
| ip | 23.27.202[.]27 | Final builds, Jun – Dec 2025; public [7, 8, 9, 10] Provenance: Previously documented | ||
| ip | 23.27.13[.]72 | Ethereum-published, Jul – Oct 2026; not found in public sources checked Confidence: Confirmed malicious | ||
| ip | 103.179.142[.]155 | Ethereum-published, Jul – Oct 2026; not found in public sources checked Confidence: Confirmed malicious | ||
| ip | 166.88.134[.]62 | Ethereum-published; public Provenance: Previously documented | ||
| ip | 23.27.13[.]135 | Ethereum-published; public Provenance: Previously documented | ||
| ip | 166.88.73[.]46 | Ethereum-published; public Provenance: Previously documented | ||
| ip | 193.247.144[.]38 | Ethereum-published; public Provenance: Previously documented | ||
| ip | 166.88.134[.]75 | Ethereum-published; public Provenance: Previously documented | ||
| ip | 91.218.183[.]174 | Ethereum-published; public Provenance: Previously documented |
| Type | Value | Context | Copy | |
|---|---|---|---|---|
| other | 0x9bc1355344b54dedf3e44296916ed15653844509 | BSC sender of all 182 encrypted payloads; public [10, 11] Provenance: Previously documented | ||
| other | TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatSe | TRON dead drop, 53 payloads; public [10] Provenance: Previously documented | ||
| other | TPDBqDKAYfRVvVYDNZVxY8CRfovkwDaSgW | TRON dead drop, 1 payload; not found in public sources checked Confidence: Confirmed malicious | ||
| other | TGJ1YJJNkFYLZKU4ZGqJfS6dU2cvGac7pS | TRON funder of four dead-drop accounts; not found in public sources checked Confidence: High-confidence suspicious | ||
| other | TQdwohPCWqqfCUaCispyV1NaUZ1HgiJPUy | TRON funder of the single-use dead drop; public [10] Provenance: Previously documented | ||
| other | 0x3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837 | Aptos fallback in chained loaders; public [10] Provenance: Previously documented | ||
| other | 0x533b2dbcaeff19cd1f799234a27b578d713d8fcaa341b7501e4526106483e0b1 | Aptos fallback in chained loaders; public [8, 9] Provenance: Previously documented | ||
| other | 0xa322E5f3D311D3080e6f0121063e9aDC2490Ef1a | Ethereum dead drop for command-and-control addresses; public Provenance: Previously documented |
Host markers: a .vscode/tasks.json that runs node on a font file on folder open; font files that are
text; build configs with long whitespace runs followed by global['_V'] or global['!']. Antivirus name
seen: Trojan:NPM/PolinRider.DB!MTB (Microsoft Defender).
What was already public
#Expand technical detail · complete record
Sources were read on or before 30 October 2026. Each one also links to its Internet Archive record, which lists the captures that exist, in case the original moves or changes.
- OpenSourceMalware, "PolinRider: DPRK Threat Actor Implants Malware in Hundreds of GitHub Repos" (7 March 2026, updated 11 April 2026: 1,951 repositories / 1,047 owners): mechanisms, history rewrite, TRON and Aptos dead drops, loader keys. https://github.com/OpenSourceMalware/PolinRider (Internet Archive lookup)
- The Hacker News, "North Korean Hackers Publish 108 Malicious Packages and Extensions in PolinRider Campaign" (4 July 2026), on Socket's research. https://thehackernews.com/2026/07/north-korean-hackers-publish-108.html (Internet Archive lookup)
- Socket, "PolinRider Spreads Through Compromised GitHub Accounts and Packagist" (17 September 2026): the Ethereum dead drop and four of its addresses. https://socket.dev/blog/polinrider-github-packagist (Internet Archive lookup)
- SafeDep, "PolinRider Switches to Ethereum C2 in 30+ Repositories" (30 September 2026): eleven server addresses, all on Evoxt (six of them Ethereum-published), stealer capabilities, spread from infected machines. https://safedep.io/polinrider-ethereum-c2-github-repositories/ (Internet Archive lookup)
- Deep Woods Security, PolinRider analysis of one open-source project (lab run 10 October 2026). https://github.com/deepwoodssec/polinrider-reactime-analysis (Internet Archive lookup)
- Proofpoint on TA416 favoring Evoxt (1 April 2026), https://www.proofpoint.com/us/blog/threat-insight/id-come-running-back-eu-again-ta416-resumes-european-government-espionage (Internet Archive lookup) ; and cyberandramen on PlugX staging infrastructure (2 March 2026), https://cyberandramen.net/2026/03/02/before-the-proxy-uncovering-active-plugx-staging-infrastructure-linked-to-three-prc-actors/ (Internet Archive lookup)
- Ransom-ISAC, cross-chain TxDataHiding crypto heist, part 3 (13 November 2025). https://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-3/ (Internet Archive lookup)
- JFrog Security Research, "Hijacked npm Packages Use Novel VSCode Autorun and Blockchain Dead Drops to Deploy a Credential/Crypto Stealer" (24 June 2026), source in the github.com/jfrog/research repository.
- Trend Micro, Void Dokkaebi fake job interview lure, with indicator list (21 April 2026). https://www.trendmicro.com/en_us/research/26/d/void-dokkaebi-uses-fake-job-interview-lure-to-spread-malware-via-code-repositories.html (Internet Archive lookup)
- Ransom-ISAC, cross-chain TxDataHiding crypto heist, parts 2 and 4 (27 October and 8 December 2025). https://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/ (Internet Archive lookup) and https://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-4/ (Internet Archive lookup)
- Google Threat Intelligence Group, "DPRK Adopts EtherHiding" (16 October 2025). https://cloud.google.com/blog/topics/threat-intelligence/dprk-adopts-etherhiding (Internet Archive lookup)
Several of these indicators are public under other names: Joyfill, Void Dokkaebi, cross-chain TxDataHiding or EtherHiding, rather than PolinRider.
Not found in the public sources I checked, as of 30 October 2026:
- the scale (40,136 proven repositories under 3,334 accounts; the largest public count was 1,951);
- the pull-request counts;
- the pusher-versus-author analysis;
- fork-based proof of back-dating and the 20 March 2025 date;
- the BSC payload corpus and its decryption;
- one TRON dead drop (
TPDB…), one TRON funder (TGJ1…) and two Ethereum-published addresses (23.27.13[.]72,103.179.142[.]155).
The Wiz and Gridinsoft pages were read; they give no counts or indicators.
Limitations
#- Static analysis only. Capabilities are read from recovered strings, not observed.
- The first pass used code search, which sees only default branches and no forks. The owner-wide expansion closed most of that gap, but seven very large fork-collector accounts were not scanned. The counts are a floor.
pushedAtis the last push, not the infection date.- The pusher analysis covers 151 of 478 repositories; the rest fell outside GitHub's event window.
- About 165 BSC payload transactions were not enumerated. Three payloads and two early config variants were not fully decoded. The known-plaintext decryption leaves about 0.1% token errors.
- Ports of the final command-and-control servers are not confirmed.
- Hosting ownership was not checked prefix by prefix.
- Attribution to North Korea comes from public reporting, not from this work.
Investigation context
#This article is part of the GitHub threat investigation. Counts are a snapshot, not evidence that the code ran on a victim's machine. The shared methodology and proof rules explain inclusion, exclusions and the independent re-check.
Claims, evidence and limits
| Claim | Assessment | Evidence | Limit |
|---|---|---|---|
| 40,136 repositories proven at a pinned commit | Confidence: Confirmed malicious | E-PR-PROOF, E-PR-VERIFY | Not stated in the finding |
| Infections arrive through rewritten history, usually pushed by someone other than the credited author | Confidence: Confirmed malicious | E-PR-FORKS, E-PR-PUSH | Not stated in the finding |
| The payload travels into other projects through pull requests | Confidence: Confirmed malicious | E-PR-PRS | Not stated in the finding |
| A 182-payload corpus on BNB Smart Chain, 179 decrypted | Confidence: Confirmed malicious | E-PR-BSC | Not stated in the finding |
| Every resolved command-and-control address is on one budget VPS provider | Confidence: High-confidence suspicious | E-PR-ETH, E-PR-RDAP | Not stated in the finding |
Already public, and what this adds
| Already public | Added here | Where to check |
|---|---|---|
| Up to 1,951 repositories under 1,047 owners (OpenSourceMalware, updated 11 April 2026). | 40,136 repositories under 3,334 accounts, each proven at a pinned default-branch commit on 30–31 October 2026. | The proof pass: 39,998 repositories |
| Mechanisms, history rewriting, TRON and Aptos dead drops and loader keys (OpenSourceMalware). | Fork-based proof of back-dating, including the 20 March 2025 date, and a pusher-versus-author analysis. | Rewritten history |
| Spread through compromised GitHub accounts and Packagist (Socket, 17 September 2026). | Pull-request counts. | Pull requests |
| The Ethereum dead drop and four of its addresses (Socket, 17 September 2026); eleven server addresses on Evoxt, six of them Ethereum-published (SafeDep, 30 September 2026). | The BSC payload corpus and its decryption. | The BSC corpus |
Terms used on this page
- pinned commit
- A specific commit, identified by its hash, at which a repository was read. Every counted repository was proven at the default-branch commit recorded in the proof pass, so a later change to the repository does not change what was proven.
- git object id
- The hash Git assigns to a file's exact contents. Recording it identifies the precise file that matched, independently of its path or of later edits.
- default branch
- The branch a repository shows by default. Counts are taken on default branches only; infected non-default branches were recorded separately and are not counted.
- inherited fork
- A fork whose malicious file is byte-identical to its parent's and was not modified in the fork. Such forks are counted and flagged, because removing the parent does not clean them; an account whose only infected repositories are such forks is listed as inherited, not compromised.
- dead drop
- A public record the loader reads to learn its next step. In PolinRider, the latest memo of a TRON account (an Aptos account as fallback) points to a BNB Smart Chain transaction whose input holds the encrypted next stage.
- fork-collector account
- An account holding thousands of forks. Seven such accounts, holding 7,500 to 89,800 repositories each, all of whose infected repositories were forks, were recorded but not scanned; the counts are a floor.
- proof pass
- The 30–31 October 2026 re-read of every candidate at a pinned commit under fixed inclusion rules, followed by an independent re-read of a random sample of 555 repositories through a different API.
- owner-wide expansion
- Listing and checking every public repository of each confirmed owner, repeated for each newly found owner until a round found none. It reaches repositories that code search does not index, including forks.
- folder-open task
- A VS Code task in .vscode/tasks.json with "runOn": "folderOpen", which runs when the folder is opened in a trusted workspace.
- workspace trust
- VS Code's setting for unfamiliar folders: a folder that is not trusted opens in restricted mode, which stops folder-open tasks.
All terms: glossary.
Corrections & discussion
Found an error, or have evidence that supports or contradicts a finding? Send a correction. Name the section and what you observed.