Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
obsidian-note-toolbar-PoC — PoC — exécution arbitraire de JavaScript pilotée par le frontmatter dans Note Toolbar pour Obsidian (GHSA-q8cw-3m8c-5pf2, CVE-2026-87002, CVSS 7.0). | Kitploit
Outils/GitHubGitHub/squeeze440/obsidian-note-toolbar-poc
Analyse StatiqueAnalyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebArticles et RechercheApprentissage et ÉducationDéveloppement de Charges Utiles
GitHub
squeeze440/obsidian-note-toolbar-poc

obsidian-note-toolbar-PoC

PoC — exécution arbitraire de JavaScript pilotée par le frontmatter dans Note Toolbar pour Obsidian (GHSA-q8cw-3m8c-5pf2, CVE-2026-87002, CVSS 7.0).

Voir le dépôt
il y a 7 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Exécution de code arbitraire pilotée par le frontmatter dans Note Toolbar via la chaîne de variables {{prop_NAME}} → {{js:}}

Statut CVE : demandé, en attente d'attribution. Cette découverte est publiée sous GHSA-q8cw-3m8c-5pf2. À l'attribution du CVE, ce dépôt sera renommé CVE-YYYY-NNNNN-obsidian-note-toolbar-PoC et cette bannière sera remplacée par le lien CVE.

ChercheurDostxodjayev Abdullox (@squeeze440)
AvisGHSA-q8cw-3m8c-5pf2
CVSS 3.17.0 (Élevé)
FaiblesseCWE-94, CWE-1336

Exécution de code arbitraire pilotée par le frontmatter dans Note Toolbar via la chaîne de variables {{prop_NAME}} → {{js:}}

Résumé

Une neutralisation incorrecte de la sortie dans le moteur de substitution de variables de Note Toolbar (plugin Obsidian) permet à un attaquant qui contrôle le frontmatter YAML d'une note (par exemple un collaborateur sur un coffre synchronisé/partagé) d'obtenir une exécution de code arbitraire sur la machine de la victime lorsque celle-ci ouvre simplement la note, en injectant une charge utile {{js: ...}} dans une propriété du frontmatter qu'un élément de barre d'outils préexistant, non-script, référence via {{prop_NAME}} dans son libellé/infobulle/lien.

Produit

Note Toolbar (note-toolbar) — plugin communautaire Obsidian Dépôt : https://github.com/chrisgurney/obsidian-note-toolbar

Version testée

v1.34.12 (commit 520271c3027eb6da38bab10a686b21e14c664c13, 2026-07-29), contre Obsidian desktop 1.13.4 sous Linux.

CVSS v3.1 estimé

7.0 (Élevé) — CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H

  • AV:L — le composant vulnérable (l'évaluateur JS du plugin, s'exécutant dans le renderer Electron d'Obsidian) n'est pas exposé au réseau ; la charge utile arrive sous forme de contenu local de coffre/fichier synchronisé par tout moyen utilisé par la victime (Git, Syncthing, Obsidian Sync, dossier partagé), ce qui est cohérent avec les découvertes antérieures de cette famille (par ex. obsidian-syncthing-integration, obsidian-codescript-toolkit).
  • AC:H — l'exploitation dépend de conditions hors du contrôle de l'attaquant qui doivent déjà exister sur l'installation de la victime : (1) le réglage « Scripting » du plugin doit déjà être activé (désactivé par défaut), et (2) la victime doit déjà avoir configuré un élément de barre d'outils dont le libellé, l'infobulle ou le lien est une référence nue {{prop_NAME}} vers une clé de frontmatter. Les deux sont des schémas d'utilisation réalistes et documentés, mais aucun n'est la configuration par défaut.
  • PR:N — l'attaquant n'a besoin d'aucun accès au système de la victime, seulement de la capacité de faire entrer une note dans le coffre de la victime avec un frontmatter contrôlé par l'attaquant.
  • UI:R — la victime doit ouvrir/visualiser la note spécifique ; aucun clic sur l'élément de barre d'outils n'est nécessaire, la barre d'outils se rend automatiquement.
  • S:U, C:H/I:H/A:H — le code s'exécute avec un accès Node.js complet (require('child_process'), système de fichiers, etc.) en tant que compte utilisateur local exécutant Obsidian.

Détails

Note Toolbar prend en charge une variable documentée {{prop_NAME}} qui substitue la valeur du frontmatter d'une note dans le libellé, l'infobulle ou le lien d'un élément de barre d'outils (skills/note-toolbar-variables/SKILL.md, wiki Variables.md). Il prend également en charge une variable {{js: <expr>}} qui évalue l'expression comme du JavaScript vivant lorsque le réglage « Scripting » du plugin est activé.

Le bug réside dans l'ordre des opérations dans src/Toolbar/VariableResolver.ts::replaceVars() :

  1. Lignes 74–92 : les espaces réservés {{prop_KEY}} sont substitués par la valeur brute de frontmatter[KEY] de la note courante — inconditionnellement, indépendamment du réglage scriptingEnabled, et indépendamment de la source de cette valeur de frontmatter.
  2. Lignes 94–104 (à l'intérieur de if (this.ntb.settings.scriptingEnabled)) : la fonction vérifie ensuite s.trim().startsWith('{{js:') sur la chaîne déjà substituée s, et si c'est vrai, retire l'enveloppe {{js:/}} et passe le reste à JavaScriptAdapter.use() pour évaluation.

Parce que l'étape 1 s'exécute avant l'étape 2 et réécrit s sur place, une valeur de frontmatter qui commence elle-même par {{js: et se termine par }} est promue de « texte affiché » à « script exécuté » — même si l'élément de barre d'outils n'a jamais été conçu comme un élément script. Le propriétaire de l'élément de barre d'outils n'a jamais tapé que {{prop_status}} ; la charge utile exécutable provient entièrement du frontmatter de la note elle-même.

JavaScriptAdapter.evaluate() (src/Adapters/JavaScriptAdapter.ts:143-205) exécute l'expression avec un véritable AsyncFunction non sandboxé :

root@kitploit:~
src/Adapters/Adapter.ts:11
protected static readonly AsyncFunction = (Object.getPrototypeOf(async function(){}) as { constructor: typeof Function }).constructor;

src/Adapters/JavaScriptAdapter.ts:164
const func = new JavaScriptAdapter.AsyncFunction("input", expression);
...
result = await Promise.resolve((func as (...args: unknown[]) => unknown)(args));

Il s'agit du véritable constructeur AsyncFunction du moteur JS, et non d'un interpréteur/sandbox — à l'intérieur du renderer Electron d'Obsidian, il dispose d'un accès complet à require()/Node.js, confirmé dans le PoC ci-dessous via require('child_process').execSync(...).

Point crucial : l'adaptateur JS est intégré et ne nécessite aucun plugin compagnon (src/Adapters/AdapterManager.ts:59 : adapter = this.js; // built-in, doesn't rely on plugin), contrairement aux préfixes de variables Dataview/Templater/JS-Engine qui nécessitent l'installation de ces plugins. Seul le propre commutateur « Scripting » du plugin (scriptingEnabled, par défaut false, src/Settings/NoteToolbarSettings.ts:300) le conditionne.

Enfin, le chemin de rendu qui déclenche la substitution est automatique, non conditionné à un clic : ToolbarRenderer.ts::renderLItems() appelle this.ntb.vars.resolveText(toolbar, file) (src/Toolbar/ToolbarRenderer.ts:418) à chaque rendu d'une barre d'outils pour une note — c'est-à-dire à l'ouverture/visualisation de la note — ce qui résout le libellé et l'infobulle de chaque élément via replaceVars(). Aucun clic sur l'élément de barre d'outils affecté n'est nécessaire.

L'affectation barre d'outils-vers-note est elle-même pilotée par le frontmatter (réglage toolbarProp, clé par défaut notetoolbar, src/Settings/NoteToolbarSettings.ts:317), de sorte qu'une note synchronisée peut sélectionner la barre d'outils qui s'y affiche — mais cela n'est pas nécessaire à l'exploitation si la victime utilise déjà une barre d'outils par défaut ou un mappage de dossier incluant l'élément vulnérable.

Ceci est distinct du risque documenté par le SECURITY.md du mainteneur lui-même (« User scripts... executes JavaScript provided by the user... intentional and by design ») — cela décrit un utilisateur qui conçoit sciemment un élément de barre d'outils {{js:}}, ou qui importe sciemment une configuration de barre d'outils partagée en contenant un. Ici, l'élément de barre d'outils n'est pas du tout un élément script du point de vue du configurateur (c'est un simple libellé d'affichage de propriété), et la charge utile exécutable arrive via le contenu/frontmatter ordinaire d'une note — le même modèle de menace de contenu de coffre non fiable que les autres découvertes d'exécution de code via synchronisation/configuration Obsidian (obsidian-syncthing-integration, obsidian-codescript-toolkit).

Preuve de concept

Vérifié dynamiquement contre une véritable instance Obsidian 1.13.4 desktop (Xvfb + fluxbox), en chargeant le plugin réellement compilé (main.js compilé depuis la source auditée), et non une simple extraction de fonction.

  1. Coffre PoCVault/ avec Project Alpha.md :

    root@kitploit:~
    ---
    status: "{{js: require('child_process').execSync('id > /tmp/ntb_poc_proof.txt; date >> /tmp/ntb_poc_proof.txt; whoami >> /tmp/ntb_poc_proof.txt'); return 'ok';}}"
    notetoolbar: Toolbar
    ---
    
  2. Plugin Note Toolbar installé, plugins communautaires approuvés, une barre d'outils nommée « Toolbar » créée via l'interface de réglages du plugin lui-même avec un seul élément dont le champ Label est {{prop_status}} (un simple libellé d'affichage de propriété — jamais configuré comme élément script).

  3. Réglage du plugin Scripting activé (opt-in de la victime, désactivé par défaut).

  4. Le simple fait d'ouvrir/visualiser Project Alpha.md — sans clic sur l'élément de barre d'outils — affiche la barre d'outils montrant ok (la valeur de retour de l'expression JS), et les commandes shell injectées s'exécutent réellement :

    Preuve terminal (~/engagements/obsidian-note-toolbar/evidence/02_terminal_proof_of_execution.png) :

    root@kitploit:~
    $ cat /tmp/ntb_poc_proof.txt
    uid=1000(kali) gid=1000(kali) groups=1000(kali),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),100(users),105(docker),992(kvm)
    Fri Jul 31 09:31:33 PM +05 2026
    kali
    

    Capture d'écran Obsidian montrant la charge utile brute du frontmatter et la barre d'outils rendue ok (~/engagements/obsidian-note-toolbar/evidence/01_obsidian_toolbar_rce_trigger.png).

    Note source conservée à ~/engagements/obsidian-note-toolbar/evidence/poc_note_frontmatter.md.

Impact

Exécution de code arbitraire complète en tant qu'utilisateur local exécutant Obsidian, déclenchée par la simple ouverture d'une note — aucun clic, aucune action explicite « exécuter le script », aucune boîte de dialogue. Dans un flux de travail en équipe/coffre partagé (Obsidian Sync, coffre adossé à Git, Syncthing, Google Drive, etc.), tout contributeur capable de modifier le frontmatter d'une note peut obtenir une RCE sur tous les autres collaborateurs ayant activé le réglage Scripting de Note Toolbar et disposant d'un élément de barre d'outils affichant une propriété de note.

Faiblesses (CWE)

  • CWE-94 : Contrôle incorrect de la génération de code (« Injection de code ») — des données de frontmatter non fiables sont concaténées dans une chaîne ensuite interprétée comme une directive de script exécutable.
  • CWE-1336 : Neutralisation incorrecte d'éléments spéciaux utilisés dans un moteur de template — la syntaxe de template/variable {{...}} ne neutralise pas les valeurs de substitution contrôlées par l'attaquant qui contiennent elles-mêmes d'autres directives de template.

Remédiation

Dans VariableResolver.replaceVars(), les vérifications de préfixe de scripting ({{js:, {{dv:, {{jse:, <%/{{tp:) devraient être évaluées sur la chaîne originale, avant substitution, et non sur la chaîne après exécution de la substitution {{prop_*}}/{{note_title}}/etc. — c'est-à-dire déterminer d'emblée si l'élément de barre d'outils lui-même a été conçu comme une directive de script, et ne jamais laisser une valeur de frontmatter substituée être réinterprétée comme telle. Concrètement : effectuer la vérification de préfixe de scripting de type hasVars avant le bloc de substitution PROP/SELECTION/NOTE_TITLE/etc., et ne pas revérifier startsWith('{{js:'/'{{dv:'/...) sur la chaîne après substitution. En défense en profondeur, les valeurs provenant du frontmatter pourraient également être échappées/neutralisées afin qu'elles ne puissent jamais réintégrer la grammaire {{...}}.

Crédit

Dostxodjayev Abdullox

Canal de signalement

Le SECURITY.md de ce dépôt confirme que le signalement privé de vulnérabilités GitHub est activé et constitue le canal préféré (« GitHub private vulnerability reporting: use the 'Report a vulnerability' button under the Security tab of this repo »), avec un formulaire Google en secours pour les rapporteurs sans compte GitHub. Revérifié indépendamment : gh api repos/chrisgurney/obsidian-note-toolbar/private-vulnerability-reporting --jq .enabled → true, et gh api repos/chrisgurney/obsidian-note-toolbar/security-advisories --jq 'length' → 0 (aucun avis antérieur, aucun risque de doublon).

Télécharger l’outil