{"dataType":"CVE_RECORD","dataVersion":"1.0","cveMetadata":{"cveId":"GCVE-110-OSM-2026-14331","assignerOrgId":"","assignerShortName":"Vulnetix","state":"PUBLISHED","datePublished":"2026-11-04T09:01:26Z","dateUpdated":"2026-11-04T05:49:32Z","dateReserved":""},"containers":{"cna":{"providerMetadata":null,"title":"","descriptions":[{"lang":"en","value":"This organisation repository was compromised twice, by two unrelated campaigns. PolinRider (DPRK) came first: a blockchain-based loader was hidden in `tailwind.config.js` on one branch, and on the other branches a hidden VS Code task runs a fake font file containing a loader that fetches code from an attacker server whose address is stored on a blockchain and runs it. GhostAction later added workflows that contain its server address. Two of the PolinRider force-pushes amended commits that carried GhostAction workflows. Anyone who ran a build or opened the project in VS Code with automatic tasks allowed should treat that machine as exposed to remotely delivered code and its credentials as compromised.\n\n# PolinRider payloads\n\nEvery PolinRider change was force-pushed by a helper script, `temp_auto_push.bat`, that copies the previous commit's author, date and message, amends the commit and force-pushes the branch, so each rewritten commit looks as old as the one it replaced. The repository's `.gitignore` is changed to hide the names of that script and its companion files. All ten force-pushes came from one user account, not from the organisation account. The repository has five branches; only `revert-4-setup/project-structure` carries no PolinRider file.\n\n## Payload 1: loader hidden in a build configuration file\n\nMalicious payload found in: `tailwind.config.js` (branch `Dinushan`)\n\nJavaScript appended to the closing line of the file after 507 spaces. Three generations were pushed. The first is the older TRON and Aptos loader. It starts from a hard-coded TRON wallet, reads its newest outgoing transaction, and uses a hidden note in it as the id of a BNB Smart Chain transaction whose data field holds the next stage. If TRON cannot be reached it falls back to an Aptos account. The next stage is decoded with a built-in key and run, once in the current process and once in a hidden `node` process. The second is the Ethereum loader. It reads the newest transaction sent by a hard-coded Ethereum wallet to learn two server addresses, requests code from the first one over plain HTTP on port 443 with a marker in a `Sec-V` request header, decodes each answer with a built-in key and runs it as JavaScript in a hidden `node` process. The server addresses are stored on the blockchain, not in the file, so the operator can change them at any time. The third is a newer version of the Ethereum loader with a second wallet.\n\n## Payload 2: VS Code launcher\n\nMalicious payload found in: `.vscode/tasks.json`\n\nA hidden VS Code task named `eslint-check` that runs automatically when the folder is opened, with its output suppressed. It starts `node` on a font-named file, and a missing `node` produces no error. Four versions (627, 661, 795 and 828 bytes) target `static/admin/css/public/fonts/fa-solid-900.woff2`, `public/fonts/fa-solid-900.woff2` or `public/fonts/fa-solid-700.otf`.\n\n## Payload 3: fake font files and a source-file copy\n\nMalicious payload found in: `static/admin/css/public/fonts/fa-solid-900.woff2`, `public/fonts/fa-solid-900.woff2` (since overwritten with a decoy on `main`), `public/fonts/fa-solid-700.otf` and `api.js` (branch `Dinushan`)\n\nJavaScript stored in a file with a font extension after a long run of blank space, so it looks empty in a viewer. The hidden VS Code task runs it with `node`. It reads the newest transaction sent by a hard-coded Ethereum wallet to learn two server addresses, requests code from the first one over plain HTTP on port 443 with a marker in a `Sec-V` request header, decodes each answer with a built-in key and runs it as JavaScript in a hidden `node` process. The server addresses are stored on the blockchain, not in the file, so the operator can change them at any time. The 700 `.otf` and `api.js` hold the newer generation, whose source is stored as a list of base64 pieces that are joined, decoded and passed to `eval`. A font-extension file and a normal-looking source file hold the same code.\n\n## Payload 4: ignore-list fingerprint\n\nMalicious payload found in: `.gitignore`\n\nHides the helper script and its companion files from `git status`.\n\n# GhostAction payloads\n\nMalicious payload found in: `.github/workflows/security-audit.yml`, `.github/workflows/repo-health.yml`, `.github/workflows/ci-check.yml` and `.github/workflows/audit.yml`\n\nEvery version contains the GhostAction server address 193[.]32[.]204[.]199. `security-audit.yml` appears in three versions, the latest carrying the batch tag `c=auto_`, and `repo-health.yml` carries `c=reinject`. No GhostAction fake font was found in this repository.","supportingMedia":null}],"references":[{"url":"https://opensourcemalware.com/threats/63687b01-7062-4701-8521-394f2e0bacb7","name":"Malicious repository: https://github.com/Wekume/Wekume-App-backend","tags":["advisory"]}],"metrics":[{"format":"CVSS_V3","scenarios":null,"cvssV2_0":null,"cvssV3_0":null,"cvssV3_1":{"version":"3.1","vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H","baseScore":9.6,"baseSeverity":"CRITICAL"},"cvssV4_0":null,"other":null}],"problemTypes":[{"descriptions":[{"lang":"en","description":"Embedded Malicious Code","cweId":"CWE-506","type":"CWE"}]}],"affected":[{"vendor":"unknown","product":"","collectionURL":"","packageName":"","repo":"https://github.com/Wekume/Wekume-App-backend","defaultStatus":"affected","versions":[{"version":"all","status":"affected","versionType":"","lessThan":"","lessThanOrEqual":"","changes":null}],"cpes":null,"modules":null,"programFiles":null,"platforms":null}],"cpeApplicability":null,"rejectedReasons":null,"replacedBy":null},"adp":null}}