From lazy-obsidian
Veille quotidienne CVE — récupère les nouvelles vulnérabilités critiques (CVSS≥7 OU CISA KEV) sur produits whitelist depuis NVD/MSRC/CISA, écrit max 5 fichiers dans _Inbox/raw/cve/ avec frontmatter Schema-conforme. Idempotent via seen_cves dans lazy-obsidian-state.json. Utilise WebFetch et PowerShell avec encoding UTF-8 systématique.
How this skill is triggered — by the user, by Claude, or both
Slash command
/lazy-obsidian:cve-veilleThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Avaler les CVE des dernières 24h (ou depuis last_run) répondant aux critères de criticité, et créer une page draft par CVE retenue dans `_Inbox/raw/cve/`. Idempotent. Plafond strict de 5 CVE par run pour éviter la pollution de l'inbox.
Avaler les CVE des dernières 24h (ou depuis last_run) répondant aux critères de criticité, et créer une page draft par CVE retenue dans _Inbox/raw/cve/. Idempotent. Plafond strict de 5 CVE par run pour éviter la pollution de l'inbox.
Set-Content -Encoding utf8 -NoNewline ou Out-File -Encoding utf8 -NoNewline. JAMAIS d'écriture en encoding par défaut PowerShell (UTF-16 LE BOM corromprait les fichiers).Get-Content -Raw -Encoding utf8 pour les fichiers JSON, -Raw pour le markdown.Add-Content -Encoding utf8 -Path <file> -Value <line>.<file>.tmp puis Move-Item -Force.Invoke-RestMethod pour les APIs JSON (NVD).Lire 99-Meta/lazy-obsidian-state.json :
$statePath = "D:\tommyDossier\Documents\Obsidian Vault\99-Meta\lazy-obsidian-state.json"
$state = Get-Content $statePath -Raw -Encoding utf8 | ConvertFrom-Json
$lastRun = $state.last_run.'cve-veille'
$seenCves = $state.seen_cves
Si $lastRun correspond à aujourd'hui (UTC, format YYYY-MM-DD) → afficher "Déjà fait aujourd'hui ($lastRun). Skip." et terminer (exit gracieux). Append une ligne SKIP_IDEMPOTENT au runs.jsonl.
start = $lastRun ou (Get-Date).AddDays(-1).ToUniversalTime() si nullend = (Get-Date).ToUniversalTime()yyyy-MM-ddTHH:mm:ss.fffZa. NVD JSON API 2.0
https://services.nvd.nist.gov/rest/json/cves/2.0?lastModStartDate=<start>&lastModEndDate=<end>
Pagination avec startIndex si > 2000 résultats (rare en 24h).
b. MSRC RSS
https://api.msrc.microsoft.com/update-guide/rss
Filtrer entrées pubDate dans la fenêtre.
c. CISA KEV catalog
https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json
Filtrer vulnerabilities[].dateAdded dans la fenêtre.
Per-source try/catch. Une source en échec n'invalide pas les autres. Logger les sources échouées dans sources_failed[] du runs.jsonl.
Liste configurable (modifier ici si besoin) :
Windows
Linux kernel
Apache HTTPD
nginx
OpenSSH
OpenSSL
Kubernetes
Docker
Microsoft Exchange
Active Directory
Match case-insensitive, substring sur les champs produit (CPE criteria pour NVD, titre/description pour MSRC/RSS).
Une CVE est retenue si TOUTES ces conditions :
$seenCvesvulnerabilities[].cveID)$retained | Sort-Object @{e='cvss';desc=$true}, @{e='date';desc=$true} | Select-Object -First 5
Plafond strict : 5 CVE par run. Si la fenêtre contient plus de 5 CVE éligibles, on garde les plus critiques (CVSS desc puis date desc).
Chemin : _Inbox\raw\cve\CVE-YYYY-NNNNN.md
Contenu (template — substituer les <…>) :
---
titre: "CVE-YYYY-NNNNN — <produit principal> <classe vuln en 3-5 mots>"
type: vulnerabilité
cluster: <cluster_inferé>
cve: [CVE-YYYY-NNNNN]
cvss_score: <float>
statut: draft
criticite: <low|medium|high|critical>
importance: standard
source_knowledge: vendor-doc
source_url: <URL NVD primaire>
tags: ["#cyber/cve", "#meta/veille-auto"]
date_maj: <YYYY-MM-DD>
---
# CVE-YYYY-NNNNN — <produit> <classe>
> [!warning] Vulnérabilité critique
> Score CVSS : <score>. CISA KEV : <oui/non>.
## Description
<Description NVD originale, traduite en français si possible, max 6 lignes.>
## Produits affectés
- <Liste CPE / versions, max 5 items>
## Source
- NVD : <URL>
- Vendor advisory : <URL si présent>
- CISA KEV : <URL si applicable>
## À investiguer
- [ ] Cluster cible définitif (parmi les 16 du Schema.md)
- [ ] Lien vers pages existantes du vault (wikilinks)
- [ ] Promotion vers `pages/{01|02|03}-…` si pertinent
Écriture impérative :
$path = "...\_Inbox\raw\cve\CVE-2026-XXXXX.md"
Set-Content -Path $path -Value $content -Encoding utf8 -NoNewline
| Mots-clés produit | Cluster inféré |
|---|---|
Active Directory, Kerberos, NTLM, LDAP | 07-IAM-ActiveDirectory |
Windows, Microsoft Exchange, Office | 02-Blue-Team |
Linux kernel | 02-Blue-Team |
Apache, nginx, OpenSSL | 05-AppSec-DevSecOps |
Kubernetes, Docker | 06-Cloud-Security |
OpenSSH | 04-Reseau-Protocoles |
| (autre / ambigu) | 99-Meta |
Mapping criticité ↔ CVSS :
criticalhighPour chaque CVE retenue :
$line = "- [veille-auto] [$cveId](_Inbox/raw/cve/$cveId.md) — CVSS $score, source NVD, ingéré $now"
Add-Content -Path "...\99-Meta\Fact-Check-Log.md" -Value $line -Encoding utf8
Si la section "## Veille automatique" n'existe pas dans Fact-Check-Log.md, la créer en append avant de logger.
$state.last_run.'cve-veille' = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
foreach ($cve in $retainedIds) { $state.seen_cves += $cve }
$state | ConvertTo-Json -Depth 5 | Set-Content -Path $statePath -Encoding utf8 -NoNewline
Si erreurs → append dans state.errors[] (FIFO max 50 entrées).
$runEntry = @{
ts = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
skill = "cve-veille"
status = "OK" # ou "PARTIAL", "FAIL", "SKIP_IDEMPOTENT"
new = $retainedCount
skipped = $skippedCount
errors = $errorCount
sources_failed = @()
} | ConvertTo-Json -Compress
Add-Content -Path "...\99-Meta\lazy-obsidian-runs.jsonl" -Value $runEntry -Encoding utf8
Statuts :
OK : ≥1 retenue, 0 erreur sourcePARTIAL : ≥1 retenue mais ≥1 source en échecFAIL : aucune retenue ET ≥1 source en échecSKIP_IDEMPOTENT : déjà fait aujourd'huiAffichage console final :
✅ cve-veille — 3 nouvelles CVE retenues, 12 filtrées hors whitelist, 0 erreurs.
- CVE-2026-12345 (CVSS 9.8) → _Inbox/raw/cve/
- CVE-2026-12346 (CVSS 8.1) → _Inbox/raw/cve/
- CVE-2026-12347 (CVSS 7.5) → _Inbox/raw/cve/
Si SKIP : ⏭ cve-veille — déjà fait aujourd'hui (2026-04-25T09:12:33Z). Skip.
Si FAIL : ❌ cve-veille — sources en échec : <liste>. Aucune CVE ingérée.
| Cause | Action |
|---|---|
| NVD 5xx / timeout | Retry x2 backoff (1s, 5s). Échec → log state.errors[], continuer avec MSRC/CISA |
| NVD parser fail | Écrire _Inbox\raw\cve\_PARSE-ERROR-<date>.md avec payload brut, log, skip |
| RSS feed down | Per-source try/catch, log sources_failed, autres sources continuent |
| Quota / 429 / 403 | Backoff 30s → 5min → abandon |
Set-Content échoue (fichier verrouillé Obsidian) | Retry après 2s. Si échec → log + skip ce CVE spécifique |
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub tommyrequillard/lazy-obsidian --plugin lazy-obsidian