Skip to content

Build1 publisher3 min readPublished

Unexplained pending pulls showed up an hour before the antivirus found the fake font

A trojan disguised as a Font Awesome font ran from a VS Code automatic task for eleven weeks and force-pushed rewritten commits into eighteen repositories, signed with the developer's own passphrase-free SSH key.

The Engineer · Build desk

Illustration accompanying Unexplained pending pulls showed up an hour before the antivirus found the fake font

What happened

  • On 6 September 2026 an antivirus quarantined a 32,874-byte file named fa-solid-400.woff2 in a marketing site's public/fonts folder, and it opened with several hundred spaces followed by JavaScript.
  • A read-only sweep of about sixty repositories found eighteen affected across three GitHub organisations, including client projects, with the first injection dated 22 June.
  • The loader ran from a hidden .vscode/tasks.json with automatic tasks enabled in settings.json, and one variant appended the same code to tailwind.config.js, vite.config.js or eslint.config.mjs.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • capability Because the tamper marks sit in commit metadata and force-push history, a team can hunt this class of intrusion with git and CI records it already owns, with no endpoint agent involved.
  • exposure The build-config variant put execution inside pipelines and Docker images, so CI runners and anyone cloning those repositories were reachable, not only the original workstation.
  • cost The expensive half of remediation is per-secret, not per-machine: twenty-seven .env files and nineteen pipelines re-keyed one credential at a time in create-verify-revoke order.
  • constraint With automatic tasks enabled, opening a folder in VS Code is code execution, so inspecting an untrusted clone safely means reading it somewhere other than the editor.

The execution path is the part worth copying into your own threat model. A `.vscode/tasks.json` in the repository declared a task that ran the fake font through Node.js as soon as the folder was opened in VS Code [12]. A `.vscode/settings.json` beside it enabled automatic tasks, so the editor never asked [13]. Both are ordinary project configuration. Both travel in a clone, which is how a collaborator picked it up in late August [9].

A second variant skipped the editor. The same code sat at the end of `tailwind.config.js`, `vite.config.js` or `eslint.config.mjs`, behind a long run of spaces, so it ran on every build, including in pipelines and Docker images [14]. The padding is also why the dropped file survived a glance: it opened with several hundred spaces before any JavaScript, weighed 32,874 bytes, and carried the name of a Font Awesome font that in reality runs past 100 KB and starts with the bytes `wOF2` [2][3].

Two symptoms beat the antivirus by about an hour. Every repository on the machine showed a pending pull the developer could not account for, and every one had triggered an overnight GitHub deployment that failed [4]. The quarantine notice arrived after that [1].

Those symptoms arrived late in the incident. The account dates the first injection to 22 June, seventy-seven days before detection, and describes fifteen projects hit in a ten-day burst at the end [7][11]. Eighteen repositories were affected in total, so if that burst is the last ten of those days, three were touched in the first sixty-seven [1]. The final malicious push landed at 15:21 the day before the sweep, while the workspace was being read [10].

The tampering is legible in git. In every affected repository the last commit had been copied verbatim, same message and same author date, with a truncated committer name and a `-0700` timezone, and the copies were force-pushed with the developer's own SSH key [8]. To GitHub that is an authorised push. A preserved author date with altered committer metadata is what a history rewrite leaves, and both fields are in `git log`.

What the account cannot do is measure anything past itself. It is one first-person report from an independent developer, published on dev.to, with no independent forensic write-up and no data from other teams [22]. It does not show that other organisations' repositories carry the same signature. It does show that here the evidence sat in a force-push history and a deployment log, both on the developer's own account [8][4].

Then the rotation. Twenty-seven `.env` files and nineteen pipelines' secrets were inventoried, and each secret was created at the provider, put in place, verified, and only then revoked, because the reverse order takes the application down [19]. Before any of that, from a phone rather than the affected workstation, every SSH key on the GitHub account was deleted, the password changed, sessions signed out, and tokens and authorised applications revoked [17]. The stolen material included passphrase-free SSH keys that opened both GitHub and the production server, the `.env` files of thirteen projects, browser-stored passwords and live sessions, and deployment secrets exposed in the pipelines the malware's own pushes triggered [15]. None of it was encrypted by anything beyond the Windows session [16].

"That is the hardest lesson of this story: cleaning the machine is only the beginning. The real remediation is making everything that was copied worthless," the author wrote [20].

What to watch

  • The promised second, more technical article would confirm the tasks.json and build-config variants of the loader.
  • An independent forensic write-up or a named malware family would let other teams match the -0700 committer signature to a known campaign.
  • Whether any of the client projects among the eighteen repositories show follow-on use of the stolen payment or database keys.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories