The scan rule that detects "Found N dynamic <script> element creations" appears to have been promoted from warning to error in the Community Plugins automated review pipeline. Plugins that previously passed scans now fail, even with no source code changes.
For Charted Roots, v0.22.39 was scanned with no errors against the release branch on 2026-05-15, then re-scanned after release tag push the same day and failed with 9 sites flagged at error severity. The bundled code is identical between the two scans.
Affected sites - example from Charted Roots v0.22.39
All 9 flagged sites are inside vendored library code, none in plugin-authored source:
| Library |
Sites |
Pattern |
core-js/internals/task.js |
2 |
IE-era setImmediate polyfill: ONREADYSTATECHANGE in createElement("script") feature detection |
pdfmake/build/pdfmake.js |
2 |
Bundled core-js with the same pattern |
jszip/dist/jszip.min.js |
4 |
UMD module detection: "onreadystatechange" in t.document.createElement("script") |
leaflet-distortableimage |
1 |
Webpack chunk loader for code splitting (chunks aren't actually used in plugin context) |
Why these are false positives
Each site is a feature-detection / module-loader pattern, not arbitrary code execution:
-
ONREADYSTATECHANGE in createElement("script") — IE-era feature detection. The created element is checked for a legacy property and discarded; it's never inserted into the DOM and never loads anything. In Obsidian's Electron runtime, the surrounding else if branch is never even entered because modern code paths above it (e.g., setImmediate in globalThis) take precedence.
-
Webpack chunk loader (__webpack_require__.l) — webpack's lazy-chunk loading infrastructure, bundled by accident when libraries are built with webpack instead of pure-output rollup/esbuild. In an Obsidian plugin context, chunks aren't loaded dynamically (single-bundle plugin output), so this function never executes.
-
JSZip UMD detection — feature-detection that selects between two implementations based on browser support. The script element is created for property-check purposes only, never injected.
None of these load external scripts. They are dead-branch / feature-detection code that exists in essentially every plugin that transitively depends on any of these libraries.
Why this matters
The scanner failure flips the plugin to a demoted state on the website (Install button disabled) and presumably in Community Plugins app once it syncs. This is a meaningful user-acquisition blocker for affected plugins, and the affected libraries (core-js, jszip, pdfmake, jspdf, canvg, anything bundled with webpack) are extremely common dependency choices.
Suggested directions
I'd love guidance on the intended path forward:
- Whitelist these specific patterns - the four mentioned above are reasonably well-known false-positive shapes.
- AST-aware analysis - distinguish "script element constructed, property-checked, discarded" from "script element with
src attribute or appendChild-inserted".
- Vendored-code carve-out - many of these are in
node_modules/.../dist/*.js files; a path heuristic could ignore non-plugin-authored code.
- Author-side fix path - if the rule is intentional, plugin authors need a documented way to handle this (forks, postbuild patches, or alternative dependencies).
Happy to provide bundle samples, AST excerpts, or reproduce against a minimal test plugin if that would help.
Plugin reference: banisterious/obsidian-charted-roots, v0.22.39.
The scan rule that detects "Found N dynamic
<script>element creations" appears to have been promoted from warning to error in the Community Plugins automated review pipeline. Plugins that previously passed scans now fail, even with no source code changes.For Charted Roots, v0.22.39 was scanned with no errors against the release branch on 2026-05-15, then re-scanned after release tag push the same day and failed with 9 sites flagged at error severity. The bundled code is identical between the two scans.
Affected sites - example from Charted Roots v0.22.39
All 9 flagged sites are inside vendored library code, none in plugin-authored source:
core-js/internals/task.jssetImmediatepolyfill:ONREADYSTATECHANGE in createElement("script")feature detectionpdfmake/build/pdfmake.jsjszip/dist/jszip.min.js"onreadystatechange" in t.document.createElement("script")leaflet-distortableimageWhy these are false positives
Each site is a feature-detection / module-loader pattern, not arbitrary code execution:
ONREADYSTATECHANGE in createElement("script")— IE-era feature detection. The created element is checked for a legacy property and discarded; it's never inserted into the DOM and never loads anything. In Obsidian's Electron runtime, the surroundingelse ifbranch is never even entered because modern code paths above it (e.g.,setImmediate in globalThis) take precedence.Webpack chunk loader (
__webpack_require__.l) — webpack's lazy-chunk loading infrastructure, bundled by accident when libraries are built withwebpackinstead of pure-output rollup/esbuild. In an Obsidian plugin context, chunks aren't loaded dynamically (single-bundle plugin output), so this function never executes.JSZip UMD detection — feature-detection that selects between two implementations based on browser support. The script element is created for property-check purposes only, never injected.
None of these load external scripts. They are dead-branch / feature-detection code that exists in essentially every plugin that transitively depends on any of these libraries.
Why this matters
The scanner failure flips the plugin to a demoted state on the website (Install button disabled) and presumably in Community Plugins app once it syncs. This is a meaningful user-acquisition blocker for affected plugins, and the affected libraries (core-js, jszip, pdfmake, jspdf, canvg, anything bundled with webpack) are extremely common dependency choices.
Suggested directions
I'd love guidance on the intended path forward:
srcattribute orappendChild-inserted".node_modules/.../dist/*.jsfiles; a path heuristic could ignore non-plugin-authored code.Happy to provide bundle samples, AST excerpts, or reproduce against a minimal test plugin if that would help.
Plugin reference: banisterious/obsidian-charted-roots, v0.22.39.