🪲: Webadmin: lack of hash / nonce for JavaScript module prevents secure CSP
What happened?
The webadmin page currently contains the following inline JavaScript Module
<script type="module">
import init, * as bindings from '/webadmin-1106c72b971bd421.js';
const wasm = await init({ module_or_path: '/webadmin-1106c72b971bd421_bg.wasm' });
window.wasmBindings = bindings;
dispatchEvent(new CustomEvent("TrunkApplicationStarted", {detail: {wasm}}));
</script>
Since this module doesn't have a hash or nonce it forces the use of unsafe-inline CSP, which is less than ideal.
How can we reproduce the problem?
I can reproduce the problem by doing the following steps:
- Implement a CSP without 'unsafe-inline' in your reverse proxy.
- Navigate to webadmin
- Page doesn't load due to CSP violation.
Version
v0.14.x
What database are you using?
RocksDB
What blob storage are you using?
RocksDB
Where is your directory located?
Internal
What operating system are you using?
Linux
Relevant log output
Code of Conduct
- [x] I agree to follow this project's Code of Conduct
The workaround I used for this, is to calculate the wasm hash manually, and add that to the CSP. I think this is for for v0.1.32, can't say for sure, since I can't figure out which version of the webadmin is deployed right now.
'wasm-unsafe-eval' 'sha256-bKabir/bcK8AMFPhuI2qkiMlTys9i33pmmaEsPhW3wA='
edit: This is not meant as a recommendation, but rather a hotfix for those that don't want to set a more broad unsafe-eval strat. I know this will break once the webadmin is updated, so you'll have to update this exception each and every time you update the admin interface. YMMV
On Mon, Nov 10, 2025 at 04:21:24AM -0800, -1 wrote:
... calculate the wasm hash manually
How?
'wasm-unsafe-eval' 'sha256-bKabir/bcK8AMFPhuI2qkiMlTys9i33pmmaEsPhW3wA='
My attempt:
$ sha256sum /usr/share/stalwart-webadmin/webadmin.zip e1b91a01ab3c250407df2f1b042fa491657045888a261ebe6129caf488c5fe73 /usr/share/stalwart-webadmin/webadmin.zip $ sha256sum /usr/share/stalwart-webadmin/webadmin.zip | awk '{ print $1 }' e1b91a01ab3c250407df2f1b042fa491657045888a261ebe6129caf488c5fe73 $ sha256sum /usr/share/stalwart-webadmin/webadmin.zip | awk '{ print $1 }' | base64 ZTFiOTFhMDFhYjNjMjUwNDA3ZGYyZjFiMDQyZmE0OTE2NTcwNDU4ODhhMjYxZWJlNjEyOWNhZjQ4 OGM1ZmU3Mwo= $
Groeten Geert Stappers
Silence is hard to parse