Repository navigation
The transaction signing path loads its code from a third-party CDN at runtime, with no SRI and no CSP #211
Description
Activity
- addedbugSomething isn't workingSomething isn't workingpriority: criticalCritical to protocol safety or mainnet readinessCritical to protocol safety or mainnet readinessarea: securitySecurity engineering and adversarial analysisSecurity engineering and adversarial analysisarea: infrastructureRPC, indexing, operations, and reliabilityRPC, indexing, operations, and reliability
on Sep 8, 2026 guptakumarranjeet150 commented
on Sep 8, 2026 ContributorMore actionsHello @SPulse-Org team,
I would love to take on this security issue regarding third-party CDN script loading without SRI and CSP pinning.
Proposed Solution:
- Subresource Integrity (SRI): Compute and pin cryptographic hashes (sha384/sha512) for external signing scripts.
- Strict Content-Security-Policy (CSP): Restrict script-src directives to explicit origin domains with fallback error handlers.
- Automated Security Tests: Add unit tests verifying SRI hash validation failure triggers and safe CSP policy headers.
Ready to submit a clean PR with passing tests within 12–24 hours. Please assign to me!
guptakumarranjeet150 commented
on Sep 8, 2026 ContributorMore actionsHi everyone,
I can tackle
The transaction signing path loads its code from a third-party CDN at runtime, with no SRI and no CSP. Proposed implementation roadmap:- Analysis: Inspect current behavior and edge cases in
SPulse-Org/SPulse - Implementation: Deliver a clean, modular solution for
The transaction signing path loads its code from a third-party CDN at runtime, with no SRI and no CSPstrictly followingSPulse-Org/SPulseconventions. - Testing: Cover changes with automated tests ensuring CI passes smoothly.
- PR: Atomic commit with clean git hygiene and passing CI
Looking forward to contributing—please feel free to assign!
- Analysis: Inspect current behavior and edge cases in
I'd like to take this issue on!
I can fix this critical security vulnerability by vendoring the transaction signing dependencies and configuring robust Security Headers for SPulse-Org / SPulse.
I will eliminate remote dynamic imports from esm.sh in frontend/soroban.js and frontend/wallet.js, replacing them with locally vendored, version-pinned modules for @stellar/stellar-sdk and @stellar/freighter-api. I will also update netlify.toml to enforce a strict Content-Security-Policy with explicit script-src, connect-src locked to approved RPC/Horizon endpoints from frontend/contracts.json, object-src 'none', base-uri 'self', and frame-ancestors 'none' to block framing attacks.
I will verify the entire transaction lifecycle locally and in preview deployments to ensure wallet connections, XDR building, and contract submissions function flawlessly without pulling any unverified remote scripts. PR ready in 1 day. Closes #211.
grantfox-oss commented
on Sep 12, 2026 grantfox-ossboton Sep 12, 2026 – with GrantFox OSSMore actions🎉 This issue has been marked as completed on GrantFox!
@guptakumarranjeet150's PR #213 was approved and merged by @Muyideen-js.
🏆 @guptakumarranjeet150: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (35 total points). Track your full progress on GrantFox.
👏 Great work, @guptakumarranjeet150! Keep contributing to SPulse-Org.
Problem
Every line of code that builds, signs, and submits a transaction is fetched from a third-party CDN
at page load, over a URL with no integrity check:
frontend/soroban.js:3--const SDK_URL = "https://esm.sh/@stellar/stellar-sdk@14.5.0?bundle",loaded via
import(SDK_URL)on line 9frontend/wallet.js:14--import("https://esm.sh/@stellar/freighter-api@5.0.0?bundle")Neither is pinned by hash. A dynamic
import()of a remote URL cannot carry a SubresourceIntegrity attribute, so there is no mechanism verifying that the bytes esm.sh returns are the bytes
the package published.
And nothing constrains where scripts may be loaded from.
netlify.tomlsetsX-Content-Type-Options,Referrer-Policy, andPermissions-Policy, but noContent-Security-Policy-- confirmed against the live response headers fromhttps://stellar-pulse.netlify.app/. There is noscript-src, noconnect-src, nodefault-src.Impact
stellar-sdkis the module that constructs the transaction, andfreighter-apiis the module thathands it to the wallet for signature. If esm.sh is compromised, or its DNS or BGP is hijacked, or
its edge cache is poisoned for this origin, an attacker controls both. They can:
address instead of the market contract
place_betinvocation for atransferof the wallet's entire XLM balanceThe user's protection at that point is reading raw XDR in the Freighter confirmation dialog, which
in practice nobody does. This drains any wallet that connects to the site, and it requires no
vulnerability in this repo's own code -- only in a dependency delivery path this repo has chosen not
to control.
The exposure is not theoretical for a CDN of this kind: unpinned, unverified runtime module loading
from a public transpiling CDN is the exact shape of the polyfill.io class of incident.
What to do
@stellar/stellar-sdkand the wallet library into the repo, or self-host them from thesame origin, so the signing path ships with the site and is reviewable in git
<script>tag carrying aSubresource Integrity hash and
crossorigin, never a bare dynamicimport()of a URLContent-Security-Policyheader innetlify.tomlwith an explicitscript-src,connect-srclimited to the Soroban RPC and Horizon endpoints infrontend/contracts.json,object-src 'none', andbase-uri 'self'rather than a silent CDN change
frame-ancestors 'none'to stop the app being framed by a look-alike siteWhy this is critical
This is the highest-severity issue in the repository. Every other bug here costs a user
correctness or convenience. This one can cost them their balance, silently, without any bug in
SPulse's own source, and there is currently no control anywhere in the stack that would stop it or
even detect it.