I want to share my personal notes just as open guidelines for me and others who may be willing to improve/implement security features, this with the intention to build around silverbullet with minimal or no intervention to the project itself
a project of this magnitude project is a huge endeavor for one maintainer: it has its own interpreter, multiple languages, layers of abstractions, different platforms and so on
to understand the scope of the project, i generated an (incomplete) sbom file using ai and put it through a scanner:
the js-yaml library has a medium severity vulnerability, CVE-2025-64718, which has been fixed. The installed version is 4.1.0, and the fixed versions are 4.1.1 or 3.14.2. The vulnerability is titled âjs-yaml prototype pollution in merge.â
the preact library has a high severity vulnerability, CVE-2026-22028, which is currently fixed. The installed version is 10.26.9, and the fixed versions are 10.26.10, 10.27.3, or 10.28.2. The vulnerability is titled âPreact: Arbitrary script execution via JSON serialization protection bypass.â
thankfully these vulnerabilities seem to have a minor or no practical impact
still there is a maintenance burden considering silverbullet has 60+ dependencies plus the requirements of a project of this magnitude
Going back to the crux of the matter, the following are just notes, sprung out personal observation, these reflect no compromise:
execution:
plugins: no verification mechanism, TODO: think about smthng simple
note: no_sandbox is implements but doesnt seem to be used, all user plugins use a web worker sandbox.
system: shell default is not sane, needs manual configuration
user: are there any ways to bypass or trigger a security issue as a user ?
external communication: needs some protection, maybe whitelisting domains somehow ?
must configure proxy to have in transit encryption
must configure auth to enable client encryption
must configure external auth to ensure modern authentication methods (eg FIDO)
pending: full review
references:
(incomplete) sbom for silverbullet version 2.3.0 and the scanner results:
This is beating a dead horse. Implementing proper safety around the current plugin api is basically impossible, while staying this powerful. Let alone with space lua libraries. There are so many apis which make it possible for a plugin to escape the sandbox + apis which kind of serve a dual use purpose: Think of writing to a page, this would obviously be needed by many plugs (think of the built-in editor plug, Silversearch which can insert links, etc.), but as soon as you allow that, plugs could write space lua to a page and quickly escape the sandbox. You could start sanitizing the output, but that would get very complex.
Silverbullet takes the same approach as operating systems, which face a similar problem, by collecting trusted packages in repositories controlled by a single trusted entity. This is also the place where SB could potentially extend itâs safety with e.g. the signing of libraries.
intercept the plugin request:
detect requests matching pattern âŚ[plugin-name].plug.js
retrieve the plugin and signature file (both use the same endpoint):
get âŚ[plugin-name].plug.js
get âŚ[plugin-name].plug.js.signature
verify if signature is valid and trusted
(the signature file could also contain the plugin manifest to perform additional checks if needed), let the original response go through
external communication protection:
just whitelisting domains for now.
implementation
silverbullet needs a minor modification, just a simple callback to a side car program in proxyHandler (proxy.go), the side car will handle all the logic and configuration files.
keep all default behavior for backward compatibility it supposed to improve security so keeping the default behavior doesnât make sense.
Thereâs probably different layers/dimensions of security here.
This:
We should update to newer versions, and monitor dependencies for security issues. This doesnât currently happen. I never looked into doing this, and help here would be appreciated. Itâs possible that using Deno rather than more standard tools like node.js for frontend builds makes this harder than it needs to be.
Managing and upgrading dependencies in general is a pain. YesâŚ
The other security dimension is SilverBulletâs âliberalâ approach to what user-written code can do.
Regarding allowing execution of shell commands â yeah, maybe this should just default to off. I think a lot of people use the Git library, which relies on it, but also here whitelisting git would be sufficient, which isnât very hard.
Then on the topic of plugs and Space Lua security:
One of the initial reasons to build SilverBullet was when I tried to implement an Obsidian plugin, and realized it was basically evaling JavaScript code in the main Obsidian process, which is of course flexible but not really safe. Not safe, but also impractical in terms of reloading behavior, you basically have to reload the app to pick up the changes. At that time I had already developed a more sandboxed approach to building plugins a few years earlier, which I thought I could dust off.
Initially I planned and partially implemented a pretty strict sandboxing boundary between plugs and SB core, but I never really made this rock solid. Later, due to reasons, I added âspace scriptâ which basically allowed to hot load random JavaScript into the SB main process. This feature was much appreciated by users because now they could extend SB however way they wanted, without me having to build explicit support for every single thing. However, it came with the obvious security risks.
In v2 I backtracked again a little bit, by removing space script and focusing on space lua, which was an environment I could control, theoretically. But also here, the temptation to offer âescapesâ (into the window object via js.window and importing arbitrary JS code into the main thread via js.import) was there, and both of those are now possible (and used a fair bit). I think they give SilverBullet a lot of power, which is great, but comes at the expense of security.
My way to âexplain awayâ these issues has been âIâm offering sharp knives.â SilverBullet is a power-user tool. If people import code from the internet in their space, theyâre responsible for knowing what it does. I think for some amount of Space Lua code this is still doable. You can reasonably go through it and understand it. For plugs itâs harder, because you import effectively âcompiledâ code and while you could inspect it or its sources, itâs likely that you wonât.
A bit of a ramble, but Iâm also still thinking about how to approach this topic.
What we can do, and perhaps this is what youâre proposing, is offer people a way to avoid a âbait and switchâ type of attack. Where you have code in your space, that loads some library from the Internet, and then that library is replaced later with something malicious. This is something is possibly preventable by adding checksum-style checks to whatever mechanisms we offer to import external code (e.g. to js.import). I think this would be a good idea. While at it, it also makes sense to cache the result of js.import so that not every client load has to make calls to external servers.
The model with library updates is that you generally point to a specific release or whatever is latest on master/stable in a repo. If some of your library authorâs github account gets hacked, malicious code gets injected and when you update⌠youâre screwed. This would be preventable by making upgrades more explicit by pinning them to specific commits/versions with checksums somehow. This would of course come at the cost of convenience. Automated updates would go out the window, if youâd have to manually check every library update every time.
We should update to newer versions, and monitor dependencies for security issues. This doesnât currently happen. I never looked into doing this, and help here would be appreciated. Itâs possible that using Deno rather than more standard tools like node.js for frontend builds makes this harder than it needs to be.
I would recommend to add a scanner to the workflows in the main repo. GitHub - google/osv-scanner-action would be an excellent choice, it uses osv.dev database, composed by multiple trusted data sources Data sources | OSV and supports various âecosystemsâ
keep in mind that you will receive several alerts and will have to judiciously consider only the relevant ones.
the only drawback, as you mentioned is that deno is not integrated, iâm currently working on a lock file converter (deno to package json) so it can be included in the osv scanner.
Regarding allowing execution of shell commands â yeah, maybe this should just default to off. I think a lot of people use the Git library, which relies on it, but also here whitelisting git would be sufficient, which isnât very hard.
I think thats a good idea
respect to plugs:
I see the history and appreciate your work, in fact it has been an amazing feat.
I worry that any opinions may expand the scope of your work, subtracting valuable time from the projectâs core
with that being said, I understand and appreciate the âsharp knivesâ philosophy. It lets us as users do what we want, and that gives us a real sense of ownership. however, we have to be careful, and Iâm not sure we all will be.
I personally would like to stay away from the client api, and only control the mechanisms that may directly introduce changes to the file system.
still really like the ideas of improving js.import and maybe packaging the plugins as a compressed file (instead of a consolidated and minified) to improve transparency (like many other do), but I think these are out of scope for this matter.
would you be open to accept a simple api to allow âhackingâ the server side ?
Iâm trying to find a lightweight solution that enables extensibility without giving you unnecessary workload
For dependencies, it doesnât look like Dependabot supports Deno, but RenovateBot does have Deno support. Maybe thatâd be worth looking at setting up to auto create PRs with updated dependencies once a week or something like that?
this give us visibility of potential vulnerabilities, so this workflow plus Deno - Renovate Docs (as @justyns recommended) could help us to take action.
the scanner can run daily, updating the dependencies as needed or once a week
deno audit can also be used to manually check deno deps
deno audit and deno-to-npm-lockfile ignore remote dependencies, leaving a significant blind spot, maybe in the next few days I will work a way to include them in deno-to-npm-lockfile
if there are any other third party libraries not listed in go.sum or deno.lock they should be accounted also