Blog
Letting users post HTML and JavaScript into a chat channel is either a great feature or a security incident waiting to happen, depending entirely on whether the sandbox around it holds. This RocketChat deployment made that bet on purpose: channels can render user-supplied HTML and JavaScript so messages carry rich content like interactive charts and custom widgets. The feature that makes the platform special is also its biggest risk, so the testing had to prove the sandbox contains that content on every client before anyone could trust it. This is the story of that quality assurance work.
RocketChat here is a cross-platform communication and collaboration platform on Web, iOS and Android, deployed and then extended with an unusual capability: channels render user-supplied HTML and JavaScript, sandboxed in an iframe on the web and in WebView components on mobile so that content cannot do harm. Around that headline feature sit the ordinary but essential parts of a chat platform, real-time messaging, access and authentication, the user, channel and message APIs, and rate-limiting.
Put simply, the defining tension is that executing HTML and JavaScript from messages is both the point and the peril. So security testing sits at the centre of the work: the sandbox is attacked directly to prove it contains malicious scripts and cannot be used to escape, steal tokens or reach other channels. Everything else is verified around that core.
A chat platform that deliberately runs user HTML and JavaScript, across three clients and in real time, concentrates risk in a few sharp places. Six problems set the testing agenda:
The sandbox was treated as the top priority and attacked head-on. Using a library of cross-site-scripting and injection payloads, the tests confirm that content rendered in a channel stays inside its sandbox: scripts cannot break out of the iframe or WebView, read or steal JWTs, call the APIs as the user, or reach other channels. The same attacks are then run against the web iframe and the iOS and Android WebViews, because a cross-platform app is exactly where containment is most likely to differ from one client to the next.
Each attack follows a fixed procedure, and the test asserts the outcome at each point in it:
On that foundation the rest of the platform is verified. The WebSocket layer is tested for delivery, ordering, reconnection and behaviour under concurrency, so real-time messaging stays reliable. Role-based access, JWTs and OAuth logins are tested so roles and private-channel memberships are enforced. Because the sandbox first has to hold in the browser, where the content renders inside an iframe, this work sits close to our web development practice, where an embedded frame running untrusted scripts is a security surface, not just a view.
The strategy tests the RocketChat clients and their HTML and JavaScript rendering, real-time and data layers at API, security, integration, real-time and cross-platform levels, with a payload-driven attack on the sandbox at its heart, all automated in continuous integration. The pieces worth calling out:
Proving a platform this security-sensitive, where the headline feature is also the attack surface, is the kind of work our software QA and testing team leads with security tests rather than bolts them on at the end.
Containing the HTML and JavaScript came down to attacking the sandbox directly with cross-site-scripting and injection payloads until it was proven to hold, with no escape and no token theft. Holding that containment on every platform meant running the same attacks against the web iframe and both mobile WebViews, so behaviour could not quietly diverge on one client. Keeping real-time messaging reliable meant testing WebSocket delivery, ordering and reconnection under concurrency. Enforcing access meant role, JWT, OAuth and private-channel membership tests, so only the right users reached the right places. Verifying the APIs meant CRUD, cascade-delete, edit-and-delete-own and pagination tests. And limiting abuse meant rate-limit and authentication-boundary tests.
The through-line was leading with security and automating it, so the most dangerous kind of regression, a hole in the sandbox, is caught immediately rather than discovered in production. Real-time collaboration platforms like this are common across SaaS and startups, where a product’s most distinctive feature is often its riskiest and has to be proven safe before it ships.
The sandbox is proven to hold on every client, the messaging is reliable in real time, the access is enforced, and the APIs behave correctly, all verified repeatably and automatically. Because the riskiest feature is proven safe and the rest is thoroughly checked, the platform can be shipped and changed with confidence, and a security regression is caught in CI on the change that introduces it rather than in the wild.
If you are shipping a platform whose best feature is also its biggest risk, you can bring on dedicated developers who have security-tested exactly this kind of system, or tell us what you are building and we will map out how to prove it safe before it goes live.
How do you test a sandbox that runs user HTML and JavaScript?
By attacking it directly. A library of cross-site-scripting and injection payloads is posted into channels, and the tests confirm the content stays inside its sandbox and cannot escape, steal JWTs, call the APIs as the user, or reach other channels. The sandbox is proven to contain the content rather than assumed to.
Why run the same attacks on Web, iOS and Android?
Because the content renders in a web iframe and in mobile WebViews, and a cross-platform app is exactly where behaviour can diverge. Running the same payloads against all three clients proves containment holds consistently everywhere the content renders, not just on the one platform that happened to be tested.
How is real-time messaging tested?
The WebSocket layer is tested for delivery, ordering, reconnection and behaviour under concurrency, so live messaging stays reliable when many users and channels are active at once, rather than only when a single conversation is open.
How is access controlled and verified?
Role-based access, JWTs and OAuth logins are tested so roles and private-channel memberships are enforced, and only the right users reach the right channels and actions. The access boundary is tested rather than trusted.
Are the APIs and rate-limiting covered too?
Yes. The user, channel and message APIs are tested for correct CRUD, cascade deletions, edit-and-delete-own rules and pagination, and rate-limiting is tested to confirm it throttles abuse without blocking normal use. The whole suite runs in CI on every change so regressions in any of these layers are caught before release.