ossf

Stars and mentions

Last 30 days, Oct 5 – Nov 3

GitHub stars77
mentions13
02468Oct 5Oct 19Nov 3
UTC days · repositories ossf owns6 repositories

Package downloads

No package download history available yet.

Top repositories

ossf’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside ossf’s account where ossf opened or reviewed pull requests in the past 365 days.

Who noticed ossf

Everyone who starred or forked ossf’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

13posts
Nov 40 posts
  1. Reddit · · r/u_angeloswif · u/angeloswif · ossf/malicious-packages

    A clean CVE dashboard says nothing about malicious packages. They live in a different database, under a different kind of ID. Every time a poisoned npm or PyPI release makes the news, someone on a security team opens their vulnerability dashboard, sees no new criticals, and relaxes a little. I understand the instinct. I also think it's measuring the wrong thing, and it's worth being precise about why. A CVE describes a flaw in software someone meant to ship. A malicious package is software that's working exactly as its author intended. Those get tracked differently. The OpenSSF Malicious Packages project, one of the main open datasets for this, says in its own scope section that vulnerability reports are out of scope. It covers typosquats, account takeovers, dependency and manifest confusion, and malicious prebuilt binaries pulled down at install time. Its entries are published in OSV format under their own "MAL" prefix. In the OSV schema's list of ID prefixes, MAL sits right alongside the distro and ecosystem vulnerability databases, but it's a different feed. CISA's Known Exploited Vulnerabilities catalog is built the same way. It describes itself as the authoritative source of vulnerabilities exploited in the wild, and tells organizations to use it as an input to vulnerability management prioritization. That's a very good list, and it's a list of vulnerabilities. A package that was hijacked for six hours last Tuesday isn't one. So "zero critical CVEs" and "none of our machines pulled the bad version" are separate claims. They need separate evidence. Disclosure: I work on Swif, and we see this split in our own product. I'd rather say so plainly than blur it. Swif's Vulnerability Detection (the first tab on the Security page, which replaced the old Device CVE Report) does exactly what it says. It reports known CVEs, vulnerable OS versions, and the most-affected packages across Macs, Windows, and Linux, using a security agent installed per platform through a Device CVE Report Policy. It's useful, and it answers the CVE question. It doesn't answer the malicious-package question, and the docs are honest about the limits. Devices only appear after their platform's policy is configured and the agent is connected. Linux coverage is x86_64 on Ubuntu, Debian, Fedora, and Arch, so no ARM. And after you patch, the data only updates on the agent's next scan. What actually helps when a MAL-style advisory drops is a different workflow: (1) Treat the advisory as an indicator, not a severity score. The question isn't "how bad is this CVE." It's "did package X, versions A through B, land on any of our machines, and when?" (2) Know where your inventory stops. Most endpoint vulnerability tooling sees installed applications and OS packages. A dependency sitting in a project's node_modules or a virtualenv under someone's home directory often isn't an "installed package" in that sense. Write down which of those you can actually see, per OS, before you need to. (3) Look for the install-time behavior, not just the package name. Malicious packages usually do their damage during install or first run. File Integrity Monitoring (changes to critical system files and, on Windows, registry keys, with hashes and permission changes) and Threat Detection (auth failures, policy changes, mapped to MITRE ATT&CK) are the signals that can show something happened even when no CVE ever gets filed. Those live on the same Swif Security page, but they're separate tabs for a reason. (4) Assume credential exposure first and work backwards. In the incidents that have hurt people most, the payload went after tokens, SSH keys, and cloud credentials on developer laptops. If a machine might have run the bad version, rotate what it could reach. Don't wait for forensics to prove it. (5) Keep the two reports apart when you present them. If a leadership update folds "vulnerabilities" and "malicious packages" into one number, the clean one will hide the scary one. None of this is a knock on CVE scanning. Patching known vulnerabilities is still the boring work that prevents most bad days. It's just a different question from "did we run something hostile," and the second one has its own feeds, its own IDs, and needs its own evidence. Curious how others handle this. Do you ingest MAL/OSV malicious-package data anywhere near your endpoint inventory, or does it only show up in your CI dependency scanning? Sources: - Swif Help Center, Vulnerability Detection (Device CVE Report) overview: help.swif.ai - Swif Help Center, Introducing the New Swif Security Page: help.swif.ai - OpenSSF Malicious Packages repository (scope and definitions): ossf/malicious-packages - OSV Schema (ID prefixes, including MAL): ossf.github.io - CISA Known Exploited Vulnerabilities Catalog: cisa.gov

    1 point
  2. GitHub Actions : le tutoriel pas à pas pour tester et publier une API Node.js Les six notions de GitHub Actions Tout workflow GitHub Actions se lit avec six mots, définis dans la page Understanding GitHub Actions de la documentation officielle (consultée le 31 octobre 2026) : | Notion | Ce que c'est | Dans notre exemple | |---|---|---| | Workflow | Un processus automatisé décrit par un fichier YAML dans .github/workflows/ | ci.yml | | Événement | L'activité du dépôt qui déclenche le workflow | push et pull_request sur main | | Job | Une suite d'étapes exécutées sur un même runner ; les jobs tournent en parallèle sauf dépendance | test et image | | Step | Une commande shell ou une action, exécutées dans l'ordre | npm ci, npm test | | Runner | La machine qui exécute un job, un seul job à la fois | ubuntu-latest, hébergé par GitHub | | Action | Une extension réutilisable, souvent prise sur le GitHub Marketplace | actions/checkout, docker/login-action | Chaque exécution part d'une machine virtuelle neuve, et chaque action du Marketplace est du code tiers qui tourne avec vos droits, d'où l'étape 6. !Schéma du workflow GitHub Actions de ce tutoriel : un événement push ou pull_request déclenche deux jobs de test en parallèle sur Node.js 24 et 26, puis un job qui publie l'image Docker sur ghcr.io --- Étape 1 : un premier workflow pour l'API Node.js Le point de départ : récupérer le code, installer Node.js et les dépendances, lancer les tests. L'API du tutoriel déclare "test": "node --test" dans son package.json et exige Node.js 24 ou plus. Créez .github/workflows/ci.yml : name: CI on: push: branches: [main] pull_request: branches: [main] permissions: contents: read jobs: test: runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v7 with: node-version: 24 - run: npm ci - run: npm test npm ci installe exactement ce que fixe package-lock.json, que le dépôt doit contenir, et npm test lance node --test. Le timeout-minutes évite qu'un test bloqué tourne jusqu'à la limite de 6 heures par job des runners hébergés, fixée par la page des limites de GitHub Actions. Pourquoi checkout v7 et pas v4 ? Selon son README, la v5 est passée au moteur node24, la v6 range les identifiants Git hors de .git/config, et la v7 refuse par défaut le code d'un fork sous pull_request_target ou workflow_run. Les dernières versions au 31 octobre 2026 sont actions/checkout v7.0.1 et actions/setup-node v7.1.0. L'onglet Actions affiche ensuite chaque exécution ; pour lire les journaux d'un runner Ubuntu, voyez nos commandes Linux de base. --- Étape 2 : tester sur Node.js 24 et 26 avec une matrice Une matrice exécute le même job plusieurs fois avec des valeurs différentes. Pour l'API, deux versions comptent : Node.js 24, minimum exigé par le package.json, et Node.js 26, passé en LTS avec la version 26.13.0 du 28 octobre 2026 selon l'index des versions de Node.js. Remplacez le job test : test: runs-on: ubuntu-latest timeout-minutes: 10 strategy: fail-fast: false matrix: node-version: [24, 26] steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v7 with: node-version: ${{ matrix.node-version }} - run: npm ci - run: npm test Les deux jobs tournent en parallèle. fail-fast: false laisse finir le second si le premier échoue. La page des limites plafonne une matrice à 256 jobs, et chaque job est facturé séparément. --- Étape 3 : le cache, plus rapide mais pas sans risque Le cache de GitHub Actions évite de retélécharger les paquets npm à chaque exécution : ajoutez cache: npm sous with. D'après le README de setup-node, la clé dérive du hachage de package-lock.json et l'action met en cache le dossier global de npm, pas node_modules. - uses: actions/setup-node@v7 with: node-version: ${{ matrix.node-version }} cache: npm Les limites, lues dans la référence du cache de dépendances le 31 octobre 2026 : - 10 Go par dépôt par défaut. Une entrée non lue depuis plus de 7 jours est supprimée. - Aucun secret dans le cache. Toute personne ayant un accès en lecture peut ouvrir une pull request et lire un cache. Le mot-clé cache-mode (read, write, write-only ou none) fixe les droits d'un job sur le cache. Il se place en tête du workflow ou dans un job, par exemple cache-mode: read sous test:, d'après la référence de syntaxe. Selon la documentation du cache consultée le 31 octobre 2026, un déclencheur peu fiable comme pull_request_target n'obtient par défaut que la lecture, et y déclarer write réintroduit le risque d'empoisonnement du cache. --- Étape 4 : secrets, variables et environnements Un jeton n'entre jamais dans le YAML : il se range dans Settings, Secrets and variables, Actions, et se lit avec ${{ secrets.NOM }}. Une valeur non sensible, comme une URL, devient une variable lue avec ${{ vars.NOM }}, au niveau du dépôt, de l'organisation ou d'un environnement, selon la page sur les variables. Pour rattacher le job image de l'étape 5 à un environnement production, avec une variable PRODUCTION_URL créée dans cet environnement, ajoutez au job : environment: name: production url: ${{ vars.PRODUCTION_URL }} La référence de syntaxe autorise le contexte vars dans url. Mais la page de gestion des environnements réserve les environnements aux dépôts publics sur GitHub Free ; en privé, il faut Pro, Team ou Enterprise. C'est pourquoi le fichier complet plus bas s'en passe. Notre workflow n'a besoin d'aucun secret ajouté à la main. Les tests de l'API fixent eux-mêmes JWT_SECRET et DB_PATH=':memory:' dans test/api.test.js, et le job image construit l'image sans démarrer le conteneur. Quant au GITHUB_TOKEN, créé pour chaque job, il suffit à publier sur le registre de GitHub. --- Étape 5 : construire et publier l'image Docker sur GHCR GHCR, le registre de conteneurs de GitHub (ghcr.io), accepte un push authentifié par GITHUB_TOKEN. L'image reprend le Dockerfile multi-étapes de notre tutoriel Docker pour débutants, basé sur node:24-alpine, placé à la racine du projet. Ajoutez ce job à ci.yml : image: needs: test if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest timeout-minutes: 20 permissions: contents: read packages: write steps: - uses: actions/checkout@v7 with: persist-credentials: false - uses: docker/setup-buildx-action@v4 - uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - id: meta uses: docker/metadata-action@v6 with: images: ghcr.io/${{ github.repository }} tags: | type=ref,event=branch type=sha - uses: docker/build-push-action@v7 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max Ce que fait chaque bloc : - needs et if. L'image n'est construite que si les deux tests réussissent, et seulement pour un push sur main. - docker/metadata-action. L'image prend le nom du dépôt, ghcr.io/<compte>/<dépôt>, soit ghcr.io/<compte>/api-taches si le dépôt s'appelle comme le dossier du tutoriel. L'action produit les tags main et sha- suivi du commit abrégé, plus les labels OCI. Son README précise qu'il met le nom d'image en minuscules, ce qu'exige le registre. - context: . avec checkout. Sans checkout, build-push-action lit le dépôt par Git et ignore les modifications des étapes précédentes, selon son README. - type=gha. Les couches Docker vont dans le cache de GitHub Actions. Avec plusieurs images, fixez un scope distinct, sinon chaque build écrase le cache du précédent, prévient la documentation de Docker. Deux pièges documentés par GitHub sur la page du Container registry. Un paquet publié pour la première fois est privé par défaut. Et le GITHUB_TOKEN ne peut pas pousser si une image du même nom a déjà été poussée à la main sans être reliée au dépôt. Côté coût, la facturation de GitHub Packages indique le 31 octobre 2026 que le stockage du Container registry est gratuit pour l'instant, avec un mois de préavis avant tout changement. L'image se déploie ensuite derrière notre reverse proxy Nginx avec Docker Compose. --- Étape 6 : GITHUB_TOKEN minimal et actions épinglées Cette étape a deux volets : limiter ce que le jeton peut faire, et figer le code des actions exécutées. Le principe du moindre privilège Le GITHUB_TOKEN est limité au dépôt et valable le temps du job. Ses droits dépendent du réglage du dépôt, puis du bloc permissions. La référence de syntaxe fixe la règle utile : dès que vous citez une permission, toutes celles que vous ne citez pas passent à none. D'où notre schéma : contents: read au niveau du workflow, packages: write dans le seul job image. C'est ce que récompense le test Token-Permissions d'OpenSSF Scorecard, qui classe ce risque comme élevé. L'option persist-credentials: false de checkout évite en plus de conserver le jeton pour les commandes Git suivantes. Épingler les actions sur un SHA Un tag comme @v7 peut être déplacé. Selon l'avis de sécurité GitHub GHSA-mrrh-fwg8-r2c3 (CVE-2025-30066), des attaquants ont redirigé en mars 2025 plusieurs tags de tj-actions/changed-files vers un commit malveillant, qui affichait les secrets dans les journaux entre le 14 et le 15 mars. La référence de sécurité de GitHub Actions recommande donc d'épingler chaque action sur l'empreinte complète d'un commit, en vérifiant qu'elle vient du dépôt de l'action et non d'un fork. La forme est uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 : l'empreinte fige le code, le commentaire garde la version lisible. Le fichier complet plus bas épingle ainsi les six actions sur les versions publiées au 31 octobre 2026. Nous avons lu ces empreintes sur l'API de GitHub ; vérifiez-les sur la page des versions de chaque action. Pour ne pas figer des versions vulnérables, laissez Dependabot proposer les mises à jour avec .github/dependabot.yml, selon la documentation de Dependabot : version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" Selon la référence de sécurité, les alertes Dependabot ignorent les actions épinglées par SHA ; les mises à jour de version, elles, fonctionnent. GitHub va plus loin avec les fichiers de verrouillage des workflows : .github/workflows/actions.lock, généré par l'extension gh actions-lock, fige le commit de chaque action, dépendances indirectes comprises, et vérifie l'identité du dépôt source. La référence de sécurité le présente comme la meilleure protection, qui remplace l'épinglage par SHA pour les dépôts qui l'adoptent. Ce tutoriel garde les SHA : la documentation ne dit pas si le dispositif est en préversion ou disponible pour tous, et il exige une extension de GitHub CLI. --- Étape 7 : concurrence et workflows réutilisables Deux mots-clés évitent le gaspillage et la copie de YAML. Le premier, concurrency, se place en tête de ci.yml : concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} D'après la page sur la concurrence, un seul workflow s'exécute à la fois par groupe, et une exécution en attente est remplacée par la plus récente. L'expression annule aussi l'exécution en cours, mais seulement pour une pull request. Sur main, l'exécution en cours va à son terme, mais une exécution en attente reste remplacée par la plus récente : seul le dernier push en file est publié. Le second, workflow_call, transforme un workflow en brique réutilisable. Déplacez le job de test dans .github/workflows/tests-node.yml : name: Tests Node.js on: workflow_call: inputs: node-versions: description: Versions de Node.js, au format JSON type: string default: '[24, 26]' jobs: test: runs-on: ubuntu-latest timeout-minutes: 10 permissions: contents: read strategy: fail-fast: false matrix: node-version: ${{ fromJSON(inputs.node-versions) }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ matrix.node-version }} cache: npm - run: npm ci - run: npm test Dans ci.yml, le job test devient un simple appel, et image garde son needs: test : jobs: test: uses: ./.github/workflows/tests-node.yml permissions: contents: read with: node-versions: '[24, 26]' La forme ./.github/workflows/{filename} est celle que la documentation sur la réutilisation donne pour un workflow du même dépôt. La même page, consultée le 31 octobre 2026, mentionne aussi une forme $/.github/workflows/{filename}, qu'elle dit recommandée et indisponible sur GitHub Enterprise Server ; nous ne l'avons pas testée. La référence des workflows réutilisables fixe dix niveaux d'imbrication au plus et 50 workflows réutilisables distincts par fichier ; les variables env de l'appelant ne sont pas transmises, et le workflow appelé ne peut pas élever les permissions reçues. --- Le fichier ci.yml complet Voici .github/workflows/ci.yml une fois les étapes 1 à 7 assemblées, avec le job test écrit en entier (sans le workflow réutilisable de l'étape 7 ni l'environnement optionnel de l'étape 4) : déclencheurs, permissions minimales, concurrence, matrice avec cache, publication sur GHCR, et chaque action épinglée sur son SHA. Sa syntaxe a été vérifiée avec le module yaml de Python ; il n'a pas été exécuté sur GitHub. Avec le workflow réutilisable de l'étape 7, le job test ci-dessous est remplacé par l'appel à tests-node.yml. name: CI on: push: branches: [main] pull_request: branches: [main] permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: test: runs-on: ubuntu-latest timeout-minutes: 10 strategy: fail-fast: false matrix: node-version: [24, 26] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ matrix.node-version }} cache: npm - run: npm ci - run: npm test image: needs: test if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest timeout-minutes: 20 permissions: contents: read packages: write steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 - uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - id: meta uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ghcr.io/${{ github.repository }} tags: | type=ref,event=branch type=sha - uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max --- Combien coûte GitHub Actions en octobre 2026 GitHub Actions reste gratuit pour les dépôts publics sur les runners standards, et sur vos propres machines. Pour les dépôts privés, la page de facturation de GitHub Actions, lue le 31 octobre 2026, exprime désormais le quota en dollars de calcul inclus, et non plus en minutes, déduits selon le tarif de chaque runner : | Offre | Calcul inclus par mois | Soit, sur Linux 2 cœurs | Stockage d'artefacts | Cache par dépôt | |---|---|---|---|---| | GitHub Free | 12 $ | 2 000 minutes | 500 Mo | 10 Go | | GitHub Pro | 18 $ | 3 000 minutes | 1 Go | 10 Go | | GitHub Team | 18 $ | 3 000 minutes | 2 Go | 10 Go | | GitHub Enterprise Cloud | 300 $ | 50 000 minutes | 50 Go | 10 Go | La conversion est notre calcul à 0,006 $ la minute. Les 2 000 minutes souvent citées, y compris dans notre guide CI/CD, correspondent donc aux 12 $ de l'offre Free sur Linux 2 cœurs ; la page de prix de GitHub affiche bien 2 000, 3 000 et 50 000 minutes pour Free, Team et Enterprise, avec Team à 4 $ et Enterprise à 21 $ par utilisateur et par mois. Le quota en dollars change la donne dès que vous quittez Linux. La grille des runners facture 0,002 $ la minute sur Linux 1 cœur, 0,005 $ sur Linux arm64 2 cœurs, 0,010 $ sur Windows 2 cœurs et 0,062 $ sur macOS 3 ou 4 cœurs. Les 12 $ de l'offre Free couvrent donc environ 193 minutes de macOS seulement. !Graphique en barres horizontales GitHub Actions : selon notre calcul, les 12 dollars inclus dans GitHub Free couvrent 6 000 minutes sur Linux 1 cœur, 2 400 sur Linux arm64 2 cœurs, 2 000 sur Linux 2 cœurs, 1 200 sur Windows 2 cœurs et 193 sur macOS 3 ou 4 cœurs > Notre calcul. Chaque job étant arrondi à la minute supérieure, notre ci.yml coûte au moins 3 minutes par push sur main et 2 par pull request. À 50 de chaque par mois sur un dépôt privé, cela fait au moins 250 minutes, bien dans le quota Free. Une matrice sur trois systèmes d'exploitation changerait tout : une minute de macOS coûte plus de dix minutes de Linux 2 cœurs. Le stockage se paie à part : 0,25 $ par Go et par mois au-delà de l'allocation d'artefacts, 0,07 $ pour le cache si vous avez relevé sa limite de 10 Go, selon la même page. --- Runners auto-hébergés : gratuits, pas sans danger Un runner auto-hébergé est une machine à vous qui exécute les jobs à la place des machines de GitHub. La page de facturation les range, le 31 octobre 2026, parmi les usages gratuits qui ne réduisent pas le calcul inclus. GitHub avait annoncé en décembre 2025 une redevance de 0,002 $ la minute sur les runners auto-hébergés à partir du 1er mars 2026, puis a écrit la reporter « pour prendre le temps de réévaluer notre approche » (notre traduction), sur sa page consacrée aux changements de prix de 2026. Selon la page sur les runners auto-hébergés, vous payez la machine et mettez à jour vous-même système et outils. Checkout et setup-node, passées au moteur node24, exigent le runner v2.327.1 ou plus selon leurs README. Un job peut y tourner 5 jours d'après la page des limites, mais le GITHUB_TOKEN ne se renouvelle que pendant 24 heures, précise la page GITHUB_TOKEN. Le vrai risque est ailleurs. Selon la référence de sécurité, un runner auto-hébergé ne garantit pas une machine propre à chaque job et peut être compromis durablement : il ne devrait presque jamais servir à un dépôt public, où n'importe qui peut ouvrir une pull request. Elle mentionne aussi des runners éphémères, dits JIT, qui n'exécutent qu'un job. Verdict : pour cette API, les runners hébergés suffisent. Notre comparatif de l'hébergement cloud pour développeurs aide à choisir la machine. --- Ce que nous n'avons pas pu vérifier Ce tutoriel est une synthèse documentaire. Restent incertains : - L'exécution des workflows. Leur syntaxe YAML a été vérifiée avec un analyseur Python, mais aucun n'a tourné sur GitHub. Testez-les d'abord sur une branche. - Le sort de la redevance des runners auto-hébergés. Reportée, mais nous n'avons trouvé aucune annonce qui l'annule. - Le prix de GitHub Pro. La page de prix lue ne l'affiche pas, ni aucun prix en euros. - Le statut exact des fichiers de verrouillage. La documentation les décrit sans préciser s'ils sont en préversion ou disponibles pour tous. - La durée réelle des jobs. Nos chiffres de minutes sont des minimums dus à l'arrondi, pas des mesures. --- Questions fréquentes Combien de minutes GitHub Actions gratuites pour un dépôt privé ? Sur l'offre Free, 12 $ de calcul par mois, soit 2 000 minutes sur le runner Linux 2 cœurs à 0,006 $ la minute, mais 193 seulement sur macOS, selon la page de facturation de GitHub lue le 31 octobre 2026. Les dépôts publics sur les runners standards et les runners auto-hébergés ne consomment rien. Quelle version d'actions/checkout utiliser ? La v7 : au 31 octobre 2026, la dernière version publiée est la 7.0.1. Épinglez-la sur son SHA complet, avec la version en commentaire. Quelle différence entre une action et un workflow ? Le workflow est votre fichier YAML, déclenché par un événement, qui contient des jobs. Une action est une brique appelée dans un step avec uses, comme actions/setup-node. Un workflow réutilisable s'appelle, lui, au niveau d'un job. Comment publier une image Docker avec GitHub Actions ? Connectez-vous à ghcr.io avec docker/login-action et le GITHUB_TOKEN, puis construisez et poussez avec docker/build-push-action, dans un job qui déclare packages: write (étape 5). --- À propos de l'auteur Abdelilah Ourti est ingénieur IA et architecte logiciel. Il conçoit et déploie des applications web et des systèmes d'IA, et publie sur NeurauTech des guides et des comparatifs destinés aux développeurs francophones. Ses autres articles sont réunis sur sa page auteur. Méthode. Synthèse documentaire fondée exclusivement sur des sources publiques consultées le 31 octobre 2026 : documentation de GitHub Actions, de GitHub Packages et de Dependabot, pages de facturation et de prix de GitHub, README et pages de versions des actions officielles et des actions Docker, documentation de Docker, OpenSSF Scorecard, avis de sécurité de GitHub, index des versions de Node.js. Les empreintes SHA ont été lues sur l'API de GitHub. La syntaxe YAML a été vérifiée localement, mais aucun workflow n'a été exécuté. Aucun lien n'est affilié et aucune relation commerciale ne lie l'auteur aux éditeurs mentionnés. Une erreur ou une version périmée ? Écrivez à contact@neurautech.com : l'article sera corrigé et la date de mise à jour modifiée. Dernière mise à jour : 31 octobre 2026. Image : Alberto Rodríguez (Unsplash License).

  3. このPRがマージされれば解消するんだが、一旦dismissするか scorecard#5247

    2 views
  4. Zennの原稿リポジトリのセキュリティ対策を、OWASPなどのガイドラインと照らし合わせた Zennの記事の原稿は、GitHubのリポジトリで管理している。 ZennのGitHub連携を使っているので、mainブランチにpushした原稿がそのまま公開される。 個人の小さなリポジトリだが、pushひとつで外に出るという点では本番環境へのデプロイと変わらない。 依存パッケージの更新はDependabotに、原稿の編集の一部はClaude Code(AIエージェント)に任せている。 どちらも、自分以外が原稿のリポジトリを変更する経路である。 悪意のあるパッケージが紛れ込んだり、エージェントが意図しない操作をしたりすれば、その結果が自分の名前で公開されかねない。 そのため、この2つの経路には対策を入れている。 ただ、自分の感覚で決めた対策には、抜けがあるかもしれない。 そこで、入れている対策を、公開されているガイドラインの項目と照らし合わせた。 この記事では、照らし合わせたガイドラインと、それぞれに対応する対策を書く。 守りたいものとリスク 守りたいものは2つある。 自分の名前で公開される内容:意図しない原稿や変更が公開されたり、公開済みの記事が消えたりしないこと 手元の開発環境:npm ciやGitフックで実行される依存パッケージのコードに、悪意のあるコードが混ざらないこと これに対するリスクは次の2つだと考えている。 依存パッケージに悪意のあるバージョンが公開され、それを取り込んでしまう AIエージェントが、意図しない公開や削除をしてしまう 照らし合わせたガイドライン OWASPとは OWASP(Open Worldwide Application Security Project)は、ソフトウェアのセキュリティ向上に取り組む非営利団体である。 2001年に始まり、現在は米国の非営利法人OWASP Foundationが運営している。 世界中のボランティアが、文書やツールをオープンソースのプロジェクトとして作っている。 成果物はすべて無料で公開されており、誰でも読める。 次に紹介するOWASP Top 10とOWASP Top 10 for LLM Applicationsも、OWASPのプロジェクトである。 owasp.org OWASP Top 10:2025 Webアプリケーションの代表的なリスクをまとめた文書である。 2025年版では「A03:2025 Software Supply Chain Failures」が3位に入っている。 依存パッケージやビルドの経路を通じた攻撃を、独立したリスクとして扱っている。 top10.owasp.org OWASP Top 10 for LLM Applications 2025 LLMを組み込んだアプリケーションのリスクをまとめた文書である。 このうち「LLM06:2025 Excessive Agency」が、AIエージェントに作業を任せるときの指針になる。 原因として、機能、権限、自律性の3つが過剰であることを挙げている。 対策として、使えるツールを最小限にすること、影響の大きい操作には人の承認を挟むこと、操作の可否をLLMに判断させず外側の仕組みで決めることが書かれている。 genai.owasp.org OpenSSF Scorecard OpenSSF(Open Source Security Foundation)は、オープンソースソフトウェアのセキュリティ向上に取り組む団体で、2020年にLinux Foundationのもとで発足した。 Scorecardはそのプロジェクトの1つで、OSSリポジトリのセキュリティ上の慣行を自動で採点するツールである。 チェック項目の一覧が、そのまま点検表として使える。 この記事では、Dependency-Update-Toolの項目を参照する。 linuxfoundation.org github.com/ossf/scorecard/blob/main/docs/checks.md 対策1:依存パッケージはDependabotのPRで週に1回更新する 対応する項目:OWASP Top 10:2025のA03、ScorecardのDependency-Update-Tool 依存パッケージの更新はDependabotに任せている。 .github/dependabot.yml version: 2 updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" groups: commitlint: patterns: - "@commitlint/*" 更新は週に1回、PRとして届く。 commitlint関連のパッケージは同時に更新しないと噛み合わないことがあるので、groupsで1つのPRにまとめている。 PRは自分で中身を見てからマージする。 package-lock.jsonはコミットしており、手元ではnpm installではなくnpm ciを使う。 lockfileに書かれたバージョンとハッシュのとおりにインストールされるので、Dependabotのマージを経ずに依存が変わることはない。 公開直後のバージョンをすぐに取り込まないことも、サプライチェーン攻撃への備えになる。 乗っ取られたアカウントから悪意のあるバージョンが公開されても、発見されて取り下げられるまでの間に取り込まなければ済むからである。 GitHubのドキュメントによると、Dependabotはバージョン更新に既定で3日のクールダウンを設けている。 日数はcooldownオプションで変えられる。 docs.github.com 対策2:AIエージェントの権限を絞り、pushの前に確認を挟む 対応する項目:OWASP Top 10 for LLM Applications 2025のLLM06 Claude Codeでは、プロジェクトの.claude/settings.jsonでツールの権限を設定できる。 設定は次のとおりである。 .claude/settings.json(抜粋) { "permissions": { "allow": [ "Bash(npx prettier:*)", "Bash(npx zenn preview:*)", "Bash(git status:*)", "Bash(git diff:*)", "Bash(git log:*)", "Bash(git show:*)", "Bash(node .claude/skills/zenn-check/check.mjs:*)" ], "ask": ["Bash(git push:*)"] } } allowに入れているのは、読み取りと検証のコマンドだけである。 これらは確認なしで実行される。 git pushはaskに入れ、エージェントがgit pushを実行する前に、自分の承認を求められるようにしている。 mainへのpushがそのまま公開になるので、LLM06の「影響の大きい操作には人の承認を挟む」に当たる。 リポジトリのルールを書いたAGENTS.mdにも、mainへのpushと、published: falseからtrueへの変更は、依頼されたときだけ行うよう書いている。 ただし、これはエージェントへの指示であって、守られる保証はない。 そのため、pushを止めるかどうかは、askという外側の仕組みで決めている。 これは、LLM06の「操作の可否をLLMに判断させず外側の仕組みで決める」にも当たる。 もっとも、askで止められるのは、git push origin mainのような普通の書き方だけである。 Claude Codeのドキュメントには、git -C . push origin mainのように書き方を変えると、git pushのルールに一致しないと書かれている。 同じドキュメントは、Bashのルールはプログラムの周りのセキュリティ境界にはならないとも書いている。 そのため、この設定はエージェントの誤操作を減らすためのものと位置づけている。 code.claude.com まとめ 照らし合わせたガイドラインの項目と、対応する対策を表にまとめる。 ガイドラインの項目 対策 OWASP Top 10:2025 A03、Scorecard Dependency-Update-Tool DependabotのPRで週1回更新、npm ci LLM06:2025 Excessive Agency 権限を読み取りと検証に限定、git pushの前に確認 ガイドラインの項目と照らし合わせておくと、それぞれの対策が何に備えたものかを説明できる。

  5. A maintained package can still ship malware. What a health check can and can't see. --- title: "A maintained package can still ship malware. What a health check can and can't see." published: true description: "A hijacked package still looks maintained, because it is. How uzomuzo now flags malicious versions from OSV, and why it marks a release after a year of silence for 7 days." tags: security, opensource, npm, supplychain --- On September 8, 2025, the maintainer of chalk and debug was phished, and malicious versions of those and other widely used npm packages were published from that account. The maintainer disclosed it within hours, and clean versions were out the same afternoon. chalk had shipped 5.6.0 three weeks earlier. By any maintenance measure, it was a maintained package. uzomuzo, the dependency health checker I maintain, judges dependencies by exactly that kind of measure. Its job is to find dependencies with maintenance or lifecycle concerns. Until v0.6.0, uzomuzo scan pkg:npm/chalk@5.6.1 returned ✅ ok … Active. A hijacked release of a maintained package is the case that kind of check can't see. This post covers the two things we added to narrow that gap, the numbers behind each decision, and what still gets through: 1. Malicious versions: read OSV's malicious-package records and stop the versions they name. 2. Before a record exists: for 7 days, mark a release that comes after a year of silence. 1. Stopping versions that OSV says are malicious The OpenSSF malicious-packages project publishes records with IDs starting with MAL-, served through OSV. For a hijack, a record usually names the specific versions that were malicious; for a package that was malicious from the start, it covers every version. Here's what uzomuzo v0.10.0 shows (output excerpt, October 26, 2026): $ uzomuzo scan pkg:npm/chalk@5.6.1 pkg:npm/chalk@5.6.2 pkg:cargo/rustdecimal@1.23.1 STATUS PURL LIFECYCLE BUILD 🔴 replace pkg:npm/chalk@5.6.1 Active ☠ MAL-2025-46969 — ✅ ok pkg:npm/chalk@5.6.2 Active Moderate 4.4 🔴 replace pkg:cargo/rustdecimal@1.23.1 Review Needed ☠ MAL-2022-1 — Three design choices are visible here. The lifecycle label doesn't change. chalk is still Active, because it is. Whether a project is maintained and whether one of its versions is malicious are separate facts, so the malicious record sits next to the label (☠ MAL-…) instead of replacing it. Other tools that read the label keep working. The match is by version. Chalk's record names 5.6.1, so 5.6.2, the clean release that followed, isn't affected by it. A flag on the whole package would push people away from the fix. (rustdecimal's record covers every version, because that package was malicious from the start.) Any CI gate catches it. If --fail-on names anything at all, a matched malicious version fails the build. A pipeline that only ever wrote --fail-on eol-confirmed will stop on chalk@5.6.1 too: $ uzomuzo scan pkg:npm/chalk@5.6.1 --fail-on eol-confirmed > /dev/null; echo $? 1 Two conditions apply. Without --fail-on, findings alone don't make uzomuzo exit with an error (command errors still do). And if the OSV lookup fails (no network, for example), uzomuzo warns that the check is incomplete; it doesn't fail the build on that alone. No waiting period uzomuzo already waits 14 days before acting on a RustSec "unmaintained" advisory, because those advisories are sometimes withdrawn and filed again. For malicious-package records there is no waiting period. Chalk's record was published about four hours after the malicious version (13:13 → 17:11 UTC, the same day). Waiting a few days before trusting such a record would let the version through during exactly the days it matters. That has a cost, and we accepted it. In June 2024, MAL-2024-2929 named react@1.0.0 and react@35.0.0 as malicious. Those versions don't exist on npm, and the record was withdrawn about six days later as "False positive caused by problematic ingestion". Nobody's build could have broken on that one. But if a record like it named a version people actually use, our rule would fail every gate on that version until the record was withdrawn. The flag clears on the next run after a withdrawal; it doesn't undo a build that already failed. What it misses uzomuzo only acts on records that say, in a field a machine can read, that the code is malicious: a MAL- ID, or a GitHub advisory tagged CWE-506 ("embedded malicious code"). ctx 0.2.6 on PyPI was hijacked in 2022. Its advisories list the affected versions and describe the takeover in prose, but none carries that classification. We considered reading the prose and decided against it: in a CI gate, misreading free text is expensive. 2. Before a record exists A record needs time to appear. We looked at npm records in the OpenSSF data (as of October 8, 2026) that name only some versions of a package, kept packages that had existed for at least a year with at least three normal releases before the malicious one, and treated those as takeovers. That left 1,556 packages. For the 1,515 of them with a usable timestamp, the median time from the first malicious publish to the earliest timestamp in its record was about 6 hours. 89% were within a day, and 98% within 7 days. That timestamp approximates when the malware was found, not when OSV started serving the record. Those figures are flattered by a few huge events. Most of the 1,556 packages belong to bulk account compromises, where one stolen account published to every package it owned and records came quickly (1,418 packages, 99% within 7 days). Outside those waves the tail is longer: of 97 packages, 86% had a record within 7 days, and 8% took more than 30 days. So for hours, sometimes for weeks, a check that only reads records says nothing. Can anything be said in that window? What these packages looked like before the attack In 737 of the 1,556 packages (47%), the malicious version was the first release in more than a year. That number needs three qualifications. - It's mostly a few events. 724 of the 737 come from 13 bulk account compromises — the Shai-Hulud waves, the September 2025 chalk/debug phishing, and others. Outside those waves, only 13 of 103 packages had been quiet for a year. - It doesn't show that attackers prefer quiet packages. On the dates of those waves, between about a quarter and a half (27–53%) of the same packages that hadn't been hit yet had also been quiet for a year. That fits bulk attacks publishing from accounts that already held many quiet packages; it says nothing about which packages attackers prefer across npm. - It compares different units. 47% is per hijacked package. Among the normal releases of the same packages, about 0.5% came after a year of silence (counting every release), or 6.8% if you look only at the last normal release before the attack. What the numbers support is narrow: a release after a year of silence is uncommon among normal releases and common among these malicious ones. That makes it a reason to look at a release, not evidence of compromise. The marker So for npm packages, uzomuzo now marks a stable release that comes after at least a year without releases. Here's a benign release that triggered it. This is an excerpt from a v0.8.0 scan captured on October 15, 2026; the marker expired on October 18, so running the command today won't show it. $ uzomuzo scan pkg:npm/dateformat@5.0.4 STATUS PURL LIFECYCLE BUILD ✅ ok pkg:npm/dateformat@5.0.4 Active ⚠ 1695d silence Moderate 5.0 The detailed view explains it: ⚠ Release after silence: This version came out 2026-10-11, after 1695 days with no release. Takeovers of npm packages that had gone quiet looked like this, and so does a maintainer who ships again after a break. No OSV malicious-package record names it yet. Before using it, check who published it (npm view <package>@<version> _npmUser). This marker clears on 2026-10-18. The verdict stays ok. We did what the message says: npm view dateformat@5.0.4 _npmUser shows the same account that published 5.0.3 four years earlier, and 5.0.5 followed on October 24. That's what a project coming back after a break looks like. The publisher check is a starting point, not proof. In a takeover the account name stays the same, and a legitimate handover changes it. Look at the release itself and at what the maintainers have said, too. The marker covers the first release after the silence, plus anything published within a day of it, since a follow-up the next day comes from the same silence. dateformat@5.0.3, the release before the silence, has no marker. Why 7 days The marker is a bridge until a record can take over. Once an OSV record names the version, the first mechanism stops it, whatever its age. !Timeline of September 8, 2025: chalk@5.6.1 and ansi-styles@6.2.2 were published maliciously within a minute. chalk had released 22 days earlier, so nothing flagged it until its MAL record about 4 hours later. ansi-styles had been silent for 1,061 days, so the release-after-silence marker would have covered it from the first minute until the record took over. Two packages from the same attack, with today's rules applied to the published timestamps. The marker only helps the one that had been quiet. So the question is: for takeovers that started with a release after a year of silence, how long did the record take? The percentages above count packages, so a bulk wave of hundreds of packages counts hundreds of times. For choosing a marker period the right unit is the incident, so we counted again: incidents whose first malicious version came after a year of silence, a bulk wave counted once, timed from the first malicious publish to when the record entered the OpenSSF data. 27 incidents qualified: 20 that touched one release line (such as 5.x), and 7 that touched two or more at once. An incident qualified if at least one of its packages matched, and the earliest publish and the earliest record can belong to different packages. So these counts describe timing per incident, not a record for every affected version. | Marker kept for | One-line incidents with a record by then (of 20) | Multi-line incidents with a record by then (of 7) | |---|---|---| | 1 day | 11 | 6 | | 3 days | 13 | 7 | | 7 days | 16 | 7 | | 14 days | 17 | 7 | | 365 days | 19 | 7 | One one-line incident has no import time; it stays in the count but never counts as recorded. The other three that took longer than 7 days took about 12.6, 57 and 310 days. Going from 7 to 14 days would have added one incident. A year would have added three, and kept every ordinary return from a break flagged for a year. So 7 days is a policy whose window held a record for 16 of the 20 one-line incidents and all 7 multi-line ones we've seen so far. It isn't proof that 7 days will be enough next time, and when the marker expires, that says nothing about whether the release is safe. This incident count is a separate selection from the package counts above. It was made outside the uzomuzo repository: the design record publishes the results and limitations, but not the full selection. Why it doesn't fail CI by default On the lockfiles of VS Code and the npm CLI, 186 of about 6,100 and 146 of about 2,600 stable releases in the year to October 2026 would have carried the marker. A team that adopts and scans every release within its first week could have run into all of them. None of them is known to be malicious. So by default the marker only shows up in the output. To fail CI on it: uzomuzo scan --sbom bom.json --show-transitive --fail-on dormant-release One exception: when a quiet package returns with releases on two or more lines at once (as node-ipc did in May 2026, with three malicious versions in 55 seconds), an Active or Legacy-Safe label also becomes Review Needed for those 7 days, so an existing --fail-on review-needed gate fails too. What it can't catch - Attacks on recently active packages. chalk itself had released three weeks earlier, so there was no silence to mark. A release cooldown can delay adopting such a version, and a matching record identifies it once one exists; neither guarantees it's caught in time. (Several other packages published from the same account that day had been quiet for years, and would have carried the marker.) - Patient attackers. An attacker who ends the silence with a harmless release, then publishes the malicious one more than a day later, walks past the marker. - Takeovers that never get a record. Some older incidents have only a GitHub advisory tagged as malicious code, which uzomuzo also reads. Some have nothing. Turn on a release cooldown too The marker can't help with the attack this post opened with. What would have helped is simply not taking a brand-new release. chalk@5.6.1 was gone from npm within about 2 hours 40 minutes, so a team that waited even one day before adopting new releases would never have installed it. So, separately from uzomuzo, we recommend a release cooldown in whatever updates your dependencies. It doesn't detect anything; it just gives the ecosystem time to notice. Dependabot (.github/dependabot.yml): version: 2 updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" cooldown: default-days: 3 Renovate (renovate.json): { "minimumReleaseAge": "3 days" } pnpm (pnpm-workspace.yaml, in minutes; pnpm 11 waits one day by default): minimumReleaseAge: 4320 Two caveats. Dependabot's cooldown applies to version updates, not security updates, so a fix for a known vulnerability still arrives right away; that's usually what you want. And a cooldown is a delay, not a guarantee: event-stream's malicious version went unnoticed for about 72 days. The two work together. A cooldown holds back every new release for a few days. The marker picks out the small share of releases that end a long silence and asks you to look at them. The MAL record stops the version once someone has identified it. In v0.10.0 we also added a quieter notice for any selected version that is 7 days old or less, in any ecosystem, when uzomuzo can find its publish time. It's always in the JSON output, and appears in the detailed view unless the release-after-silence marker or a malicious record already covers the version. It doesn't change the verdict or fail CI. It tells you that you're early, before records have had time to arrive. Try it go install github.com/future-architect/uzomuzo-oss/cmd/uzomuzo@v0.10.0 # or download a release binary export GITHUB_TOKEN=... # optional; adds commit history and repository signals # One package uzomuzo scan pkg:npm/chalk@5.6.1 # A whole project, via a CycloneDX SBOM trivy fs . --format cyclonedx | uzomuzo scan --sbom - --show-transitive --fail-on malicious Include --show-transitive. Without it, uzomuzo skips the dependencies your SBOM marks as transitive, and chalk and debug usually arrive as transitive ones. What gets checked also depends on what your SBOM contains. The malicious-version check needs v0.6.0 or later, and the release-after-silence marker v0.7.0 or later. The design records behind this post are ADR-0027 and ADR-0028. --- Earlier posts on uzomuzo: "Your dependencies are 48% unmaintained — and SCA tools can't see it" and "Your CI runs other people's code. Is anyone still maintaining it?" Kota Kanbe — Creator of vuls, an open-source vulnerability scanner, and maintainer of uzomuzo.

    2 comments
  6. YouTube · · YouTube description · Coding with Preet · ossf/scorecard

    GitHub Actions Security Audit: A 30 Minute Pipeline Checklist A thirty-minute audit, our own framework and not an industry standard, covers token permissions, risky triggers, secrets, caches, action pinning, npm publishing, install defaults and alerting on your own publishes. Detection and response matter too: rotate exposed credentials, and treat tools such as Scorecard and SLSA as prompts, not guarantees. Episode 7 of 7 in the series 'CI/CD Supply Chain Security: GitHub Actions and npm After the 2026 Attacks'. CHAPTERS 0:00 Who notices first? 0:44 Log what leaves the runner 1:31 Assume exposed, then rotate 2:30 Tools help, but have limits 3:25 Minutes zero to fifteen 4:19 Minutes fifteen to thirty 5:13 Seven episodes, one checklist QUICK ANSWERS Q: How do I respond if a compromised package was installed? A: TanStack's postmortem recommends rotating cloud, Kubernetes, Vault, GitHub, npm and SSH credentials reachable from the install host, and CISA's tj-actions alert says to rotate identified secrets immediately. Q: What does the GitHub Actions network firewall do? A: GitHub's July 2026 post says the technical preview logs all outbound network traffic from workflow runs to detect unusual behaviour, with egress restrictions described as future work (status as of that post; re-check). Q: What can OpenSSF Scorecard and SLSA tell me? A: Scorecard has checks such as Dangerous-Workflow and Token-Permissions for workflow risks. SLSA describes incrementally adoptable supply chain guidelines and states that it does not address organizations that intentionally produce malicious software. KEY FACTS AND SOURCES - TanStack postmortem: no internal alerting; the compromise was learned of from a third party. - GitHub (July 2026): the Actions network firewall, in technical preview at that time, logs all outbound traffic from workflow runs. - SLSA documentation: SLSA does not address organizations that intentionally produce malicious software. Source: Postmortem: TanStack npm supply-chain compromise (TanStack, 2026-05-11): tanstack.com Source: Disrupting supply chain attacks on npm and GitHub Actions (GitHub Blog, 2026-07-28): github.blog Source: Secure use reference (GitHub Docs): docs.github.com Source: Supply Chain Compromise of Third-Party tj-actions/changed-files (CISA): cisa.gov Source: OpenSSF Scorecard checks: github.com/ossf/scorecard/blob/main/docs/checks.md Source: About SLSA (SLSA specification v1.2): slsa.dev Source: Trusted publishing for npm packages (npm Docs): docs.npmjs.com SERIES Previous episode: youtu.be Full series playlist: youtube.com Figures and claims in this series come from public job-posting analyses, career guides and interview-prep sites. They are approximate and change quickly, so check current postings before making decisions. Disclosure: the narrator's voice and the on-screen presenter are AI-generated (synthetic media). #GitHubActions #DevSecOps #CICD

    3 views
  7. YouTube · · YouTube description · Coding with Preet · ossf/scorecard

    Pin GitHub Actions to a SHA: Lockfiles and Immutable Releases Tags and branches can move, so GitHub's documentation recommends pinning actions to a full-length commit SHA, and says workflow dependency lockfiles, in public preview as of October 2026, go further by covering transitive dependencies. Publishers can use immutable releases so tags and assets cannot change. Episode 3 of 7 in the series 'CI/CD Supply Chain Security: GitHub Actions and npm After the 2026 Attacks'. CHAPTERS 0:00 Tags can move 0:45 A hash fixes the code 1:29 Pinning is not the whole answer 2:19 Lock every action, even nested 3:12 Enforce it, but pilot first 3:52 Publishers can lock releases too 4:43 Recap and next QUICK ANSWERS Q: Should I pin GitHub Actions to a commit SHA? A: GitHub's secure use documentation says to pin third-party actions to a full-length commit SHA, verifying the SHA comes from the action's own repository. It also says tags can be moved or deleted if the repository is compromised, and its lockfile documentation says SHA pinning in workflow files is no longer necessary for repositories that adopt a lockfile. Q: What is a GitHub Actions workflow dependency lockfile? A: A file generated by a GitHub CLI extension that pins a commit SHA to every action, including transitive dependencies, and every reusable workflow. GitHub's documentation says it is in public preview and subject to change (as of October 2026). Q: What are immutable releases? A: GitHub's documentation describes releases whose assets and Git tag cannot be changed after publication, with an automatically generated release attestation. KEY FACTS AND SOURCES - GitHub Docs: a tag can be moved or deleted if a bad actor gains access to the repository storing the action. - GitHub (March 2026 roadmap): commit SHAs help but are hard to manage at scale and transitive dependencies remain opaque. - GitHub Docs: workflow dependency lockfiles are in public preview and subject to change (as of October 2026). Source: Secure use reference (GitHub Docs): docs.github.com Source: Workflow dependency lockfiles (GitHub Docs, public preview): docs.github.com Source: Enforcing workflow lockfiles (GitHub Docs): docs.github.com Source: Immutable releases (GitHub Docs): docs.github.com Source: What's coming to our GitHub Actions 2026 security roadmap (GitHub Blog, 2026-03-26): github.blog Source: OpenSSF Scorecard checks: github.com/ossf/scorecard/blob/main/docs/checks.md SERIES Previous episode: youtu.be Full series playlist: youtube.com Figures and claims in this series come from public job-posting analyses, career guides and interview-prep sites. They are approximate and change quickly, so check current postings before making decisions. Disclosure: the narrator's voice and the on-screen presenter are AI-generated (synthetic media). #GitHubActions #DevSecOps #SupplyChainSecurity

    11 views
  8. Anthropic's OSS Scanner Emails Bug Reports No Human Has Read. Give It a Threat Model - Book: Prompt Engineering Pocket Guide - Also by me: Thinking in Go (2-book series) — Complete Guide to Go Programming + Hexagonal Architecture in Go - My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools - Me: xgabriel.com | GitHub --- Anthropic will scan your open-source project for security bugs at no cost. The catch is written into its own announcement: the reports "are model-generated and sent without human review". The service is called OSS Scanner. Anthropic announced it on October 8, and on October 19 the company's ClaudeDevs account announced it to developers on X. Anthropic's Cyber Mission announcement says enrolled projects get periodic scans from Anthropic's most capable models, "free of charge". The launch post names Claude Mythos among those models. If you maintain a project that might qualify, look closely at the three files the scanner reads. One of them decides how loud the reports will be. What lands in your inbox Per the repository README, the scanner builds your project in an isolated VM, analyzes it with no Internet access, and emails what it finds to your primary_contact and any CCs. Each report carries a reproducer and, where available, a proposed patch. The launch post adds an explanation of the bug and, where possible, a bisection to the commit that introduced it. Because no human checks these reports, Anthropic puts no 90-day disclosure clock on them, and the README says it "will not make them public". A clock only starts if a finding is later validated through Anthropic's coordinated disclosure process. Per the FAQ, it may then be disclosed 90 days after you are told about the human validation. The FAQ also says Anthropic may later set a disclosure period on some high-severity reports, with advance notice and an opt-out. On the data side, the FAQ says the scanning agents run in hardened sandboxes with internet access disabled, and that reports sit in an isolated cloud project only the Anthropic security staff who need them can reach. How good are unreviewed reports? Anthropic publishes its own numbers, and they are worth reading as exactly that. Over six months its models produced more than 29,000 candidate vulnerabilities. Its team manually reviewed and triaged about 6,000, and it sent nearly 5,000 reports, unvalidated ones included, to maintainers who asked for everything (Anthropic). To check accuracy, Anthropic's penetration testers reviewed 97 critical and high-severity findings across 48 projects. 85 of them (88%) met the bar for its disclosure process. Of the other 12, 11 were real bugs that duplicated known issues or other findings from the scan, and one was a false positive (Anthropic). Anthropic ran that check itself, on an early version of the scanner, so treat 88% as a vendor figure, not an independent audit. Security Affairs repeated the figures on October 9. The maintainers quoted in the launch post are positive. The wolfSSL quote: "of the 74 reports we received, all but two were valid, and five became CVEs." The OpenSSL Corporation quote says a report with a real exploit attached is "basically job done for an engineer". The same post also says some maintainers found severity ratings inflated, or felt the scanner misread their threat model. The Cyber Mission announcement says some reports will carry a wrong severity, and that Anthropic expects a "true-positive rate above 90%". Enrolling is a pull request with three files Core maintainers enroll by opening a PR to anthropics/oss-scanner that adds one directory, projects/<name>. Per the FAQ, eligibility follows criteria similar to Google's OSS-Fuzz: project age and update frequency, OpenSSF criticality score, an open-source license, usage, and the sectors the project serves. The FAQ adds that brand-new projects typically don't qualify, and that a human checks you are a core maintainer and that the contact is a genuine project security contact, for example one listed in SECURITY.md. Here is a project.yaml adapted from the template, for a hypothetical library: # projects/libexample/project.yaml repo: https://github.com/example/libexample#main primary_contact: security@example.com homepage: https://example.com disabled: false dockerfile: .oss-scanner/Dockerfile threat_model: .oss-scanner/threat_model.md Use a security alias for primary_contact: the README warns that email addresses in project.yaml are public. If you add a pgp key, the template says every report is encrypted to it and goes to primary_contact only, so pgp can't be combined with auto_ccs. In the Dockerfile, the network exists only while the image builds. The Dockerfile template says everything an agent might need to run your tests must be fetched there. The template also copies your checkout to /src and builds with debug info and frame pointers. Before you open the PR, the README asks you to run two checks from the repo root: tools/validate.py checks your projects/<name>/ directory against the rules, and tools/check <name> builds the project the way the scanner will, then opens a shell in the finished image with no network. Work from your own fork, since the PR comes from there. # your fork of anthropics/oss-scanner git clone https://github.com/YOUR-USER/oss-scanner cd oss-scanner mkdir -p projects/libexample cp templates/project.yaml projects/libexample/ # edit projects/libexample/project.yaml, then: tools/validate.py tools/check libexample tools/check runs your Dockerfile with network access, as docker build would, and installs Claude Code into the image it builds, as the scanner does. The README tells you to check only projects you trust, so read the Dockerfile before you run it. Write the threat model before the first scan threat_model.md is optional, and the README calls it strongly recommended. It is the file that tells the scanner how you rate severity, for example whether post-auth SQL injection counts as high or critical for your project. Inflated severity is the complaint Anthropic itself reports, so this is the file to write first. The template has five sections. A filled-in version for a hypothetical image decoder: Threat model ============ What this project does and where untrusted input enters ------------------------------------------------------- * An image decoder. Every input file is untrusted. Components that matter most / least ----------------------------------- * src/decode/ matters most. tools/ is a CLI wrapper. * vendor/ is third-party code and out of scope. How to exercise it ------------------ * examples/decode_file reads one file from argv. How you rate severity --------------------- * Any out-of-bounds write is high at minimum. * Controlled overflow that may lead to RCE is critical. * All DoS is medium. Anything to leave alone ----------------------- * Slow decoding of huge images is expected. You are writing instructions for a model here. Name what is in scope and how to run your code, and list the cases you don't want reported. Leave it vague and you get the scanner's own idea of severity, unfiltered, in your inbox. Pausing, leaving, and whether to enroll at all To pause reports, set disabled: true. To leave, delete projects/<name>/. After you opt out, the FAQ says you go back to Anthropic's standard disclosure process. Credit is not required. If you patch a finding, the FAQ asks for a line naming the report ID, in a format like ANT-2026-ABCD1234. If your project lacks the people to triage a stream of model-written reports, wait. The Cyber Mission announcement says the service "is meant for projects with the capacity to keep up with surfaced findings", and that projects without that capacity keep getting human-verified disclosures. For the patching work, Anthropic also offers qualifying projects six months of free Claude Max 20x through Claude for OSS. Would you enroll a project you maintain, knowing the first human to read each report is you? Tell me in the comments. --- If this was useful I build Hermes IDE, so weigh this with that in mind: if you hand a scanner report to Claude Code or Codex to reproduce and patch, Hermes can give each task its own branch and worktree, so the fix stays apart from your other work. It's free on macOS, Windows and Linux: download it or read the source on GitHub. The scanner reads threat_model.md to decide what matters and how loudly to report it, so the way you write that file shapes what lands in your inbox. The Prompt Engineering Pocket Guide covers writing instructions like that, so a model does what you meant. ![Prompt Engineering Pocket Guide: Techniques for Getting the Most from LLMs](amazon.com)

  9. SBOM Minimum Elements in Practice: What Breaks After the First Release SBOM Minimum Elements in Practice: What Breaks After the First Release Software bills of materials (SBOMs) moved from a niche supply-chain practice to a procurement expectation. Generating one is no longer the hard part. Keeping them accurate enough to answer a question during an incident is. The commonly cited baseline comes from the minimum-elements work that fed into NIST guidance on software supply-chain security, and the fields are unglamorous: supplier name, component name, component version, other unique identifiers, dependency relationship, author of the SBOM data, and a timestamp. Formats such as SPDX and CycloneDX carry those fields. The operational failure modes show up later. Unique identifiers are where matching succeeds or fails Two identifier systems dominate practice, and they are not interchangeable. Package URLs describe ecosystems precisely, including namespace, package name and version. Common Platform Enumeration identifiers describe products in a way vulnerability databases understand. A pipeline that emits only ecosystem identifiers will produce SBOMs that read well and correlate badly, because vulnerability matching often relies on product identifiers or on vendor advisories that name a product rather than a package. The practical fix is to emit both where the tooling supports it, and to record the mapping explicitly. When a tool cannot resolve a product identifier, that gap belongs in the SBOM record rather than being silently dropped, because every downstream match inherits the uncertainty. Version normalisation and dependency completeness Build systems rewrite versions. A component pinned as a range, resolved by a lockfile, and patched by a re-resolution step can appear in three different forms across three releases. Normalisation rules need to be written down, and the SBOM needs to state which stage it describes: source, build input, or deployed artifact. Transitive dependencies are the second gap. An SBOM that lists direct dependencies only will miss the library that actually carries a flaw. Depth limits, vendored copies and statically linked binaries are common blind spots, and generated code from templates or code generators rarely appears at all. Timestamps, authorship and drift The timestamp field matters more than it looks. Without it, nobody can tell whether an SBOM describes the artifact currently running or a superseded build. Automating generation at release time, with the artifact hash recorded alongside, removes that ambiguity. Drift is the quiet problem. SBOMs describe builds; systems run containers, virtual machines and installed packages that change after deployment. Reconciling the two requires either runtime inventory or an honest statement that the SBOM covers the release artifact only. NIST SP 800-218 frames this work as part of secure software development practice rather than a documentation exercise, which is the right framing: the SBOM is only useful if some process consumes it. Making the data earn its place Three habits turn an SBOM programme from paperwork into capability. First, validate the SBOM against the build on a schedule, not only when a customer asks. Second, connect it to an asset inventory so that a new advisory can be traced to affected systems rather than affected repositories. Third, record exploitation context for the affected components instead of forwarding raw match lists, because a list of hundreds of matches without triage exhausts the team that has to act on it. None of this requires exotic tooling. It requires deciding who owns the produced data, what question it must answer, and how quickly. An SBOM that answers one question well beats a complete file nobody queries. References - NIST, Secure Software Development Framework (SP 800-218): csrc.nist.gov - OWASP, Vulnerable Dependency Management Cheat Sheet: cheatsheetseries.owasp.org - OpenSSF, Scorecard: ossf/scorecard - CISA, Known Exploited Vulnerabilities Catalog: cisa.gov

    1 comment
  10. OpenSSF Scorecard v5.6.0 and scorecard-action v2.5.0 are out! 🎉 This is the first Scorecard release since our hosted services (the weekly scans and the REST API) moved to AboutCode Foundation infra! If you use the GitHub Action, upgrade to v2.5.0! Scorecard v5.6.0: github.com/ossf/scorecard/releases/tag/v5.6.0

    2 reposts
Trending awards, every completed day and week
Gold
01st place finishes
Silver
02nd place finishes
Bronze
03rd place finishes
Awarded repositories
0Owned by ossf now

No trending awards yet

None of the repositories ossf owns has finished in the top three of a completed trending day or week, by stars, forks or PR authors. See who is trending now.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.