Introduction
Recently, an external red team (security) discovered a unique vulnerability in an application I maintain.
All other work on this project has stopped until we get it not just patched, but appropriately fixed.
The initial patch was simply a means of plugging the hole. It is intended to be temporary and something we can get in place quickly. While thinking about the patch, I had an odd thought.
My thought, "Can lazy loading be used to protect our sensitive code?"
Lazy loading has always been a means for me to make my code run faster and more efficiently. In most cases, I've skipped using it unless there was a specific need for a faster implementation.
With the thought of protecting sensitive code in mind, I began conducting some research...
Lazy Loading
Implementing Lazing Loading in Angular - GeeksForGeeks.
Server-Side Rendering
Applications that rely heavily on server-side rendering typically do not experience this issue.
The login page is rendered and shown. Once logged in, the server-side will present the sensitive pages as needed. If correctly designed, they will only load the content and endpoints required.
Angular
Angular lazy loading is a technique used to improve the performance of Angular applications by loading modules or components only when they are needed, rather than loading everything at the initial application startup.
This includes:
- Module splitting
- Route configuration
- On-demand loading
The benefits are:
- Faster initial load times
- Improved performance
- Reduced bandwidth usage
Implementing Angular Lazy Loading ...
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) },
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Angular (in newer versions) also allows for the lazy loading of individual components or parts of templates using the defer block. This offers even finer-grained control over when content is loaded, with options for triggers and placeholders.
React
React lazy loading, also known as code-splitting, is a performance optimization technique that allows you to defer the loading of specific components until they are actually needed. This significantly reduces the initial bundle size, improving the application's loading time and overall performance.
This includes ...
- Reduced initial loading time
- Improved performance
- Optimized resource usage
The benefits are ...
- Large or complex components
- Route-based code splitting
- Components with heavy dependencies
How to implement React lazy loading ...
React provides built-in features, React.lazy() and Suspense, for implementing lazy loading.
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
);
}
Vue and more
Vue does something similar to React. I won't rehash that for simplicity's sake.
I was asked about lazy-loading JavaScript code that should be protected natively. This is an interesting side track that I haven't explored yet, but I might delve into it in a future article.
Safe Lazy Loading
My research was shocking ... to me.
Only one of the frameworks or libraries even hinted at using lazy loading for security reasons, "code splitting." Security was not mentioned.
In a more recent conversation, I realized that applications rendered server-side would be more protected by the implementation I'm discussing here.
The sensitive code isn't returned until proper authentication occurs. Having said this, we still need to be careful about how much of the application is loaded; are we exposing more code than is necessary, even to logged-in users?
Implementation
I've been exploring Microsoft's MSAL tooling and came across this code. There's nothing complicated here ...
function App() {
const request = {
loginHint: "name@example.com",
scopes: ["User.Read"]
};
const { login, result, error } = useMsalAuthentication(InteractionType.Silent, request);
useEffect(() => {
if (error) {
login(InteractionType.Popup, request);
}
}, [error]);
const { accounts } = useMsal();
return (
<>
<p>Anyone can see this paragraph.</p>
<AuthenticatedTemplate>
<p>Signed in as: {accounts[0]?.username}</p>
</AuthenticatedTemplate>
<UnauthenticatedTemplate>
<p>No users are signed in!</p>
</UnauthenticatedTemplate>
</>
);
}
... but ...
The code <p>Signed in as: {accounts[0]?.username}</p>, while not an issue as written, could just as easily be <complex-application /> that has tons of JavaScript available that could expose threat vectors.
In my opinion, this is the ideal scenario to utilize the <Suspense> element and React.lazy() functionality to protect the code.
Thoughts
There is definitely more that I need to consider. There is definitely more research that I need to do. There's a depth of authentication and authorization that needs to be taken into account to protect the client's code and data appropriately.
Having recently gone to a talk on "Data Validation and Sanitation by Claire Bourdon, I'm thinking of this as a "lifecycle" of security - maybe it's a "generational" handling. Whatever it's called, I'm realizing that there's more depth to protecting my code than I saw before.
Examining the traditional SPA methodology, where everything is loaded at once, reveals "all code," including code that should be secure. Using LAZY LOADING allows us to protect that code in a much more meaningful way. This isn't a complete security solution, but it's a significant step that should be taken into account when developing frontend code.
Whenever code is loaded into the browser, it can be read or scanned. Sensitive information can be exposed unintentionally. We should limit exposure by using lazy loading and not solely relying on server-side security operations.
My thought now is, "Should lazy loading be used to protect our sensitive code, beyond what is done server-side?"
It absolutely should be used for improved code security.
Please let me know your thoughts.

Top comments (19)
Who is still bundling all the frontend code in one file? With all main browsers supporting dynamic imports it is a antiquated best practice.
Why have sensitive code in the frontend in the first place? When the code is sensitive it should be in the backend to have no exposure.
Lazy loading is not stopping that. API endpoints should have security measures in place to prevent that.
All javascript code send to the browser is public, so thinking it is possible to use it as a security measure sets you up for failure.
David, bundling code has been the default for a long time. I'm not saying it's current practice (i.e. Angular implements lazy loading by default), but there's a LOT of legacy code out there that can be improved.
There has to be "some" sensitive code in the frontend to reach the backend - API URLs, potentially keys, and possibly more with poor designs. Not all security should be in the backend.
Lazy loading absolutely can protect information if done correctly. I think it's naive to think otherwise.
The ultimate idea I am proposing here is to limit what protected information is visible and when. Ignoring what has to be done in the frontend because the backend is "secure" would be my idea of setting yourself up for failure. It all should be protected end-to-end.
Thank you for the thoughts ...
As I mentioned before API urls should have security measurements, otherwise lazy loading code is not preventing misuse.
If there is a man in the browser attack all the API urls can be exposed, and when they see the endpoints don't have security measurements there can be a data breach.
But even without an attack the filename of the lazy loaded modules can be found in the initial code and can be downloaded to find urls.
That is my worst nightmare, a key that can be found in javascript code. This is one of the reasons there is a backend/frontend divide.
You don't want people to make request with your key, this can lead to not being able to use the API because bots are hammering it with your key.
Lazy loading on its own doesn't protect information. It can defer asking for information, but that is security by hiding. And that is one of the weakest security measurements.
It is the same boat as frontend validation. If it is not backed up by backend validation, it is only half of a security measure.
I agree that the frontend can be responsible for a bit of the security tasks, but it should be the backend that evaluates when the situation is secure enough to push the information to the browser.
A website is loaded in many unsecured applications, so it is much easier to undo frontend security measures.
I think looking at in-browser behaviour as security without mentioning the backend side of the coin, is a dangerous way to promote security.
I'm never promoting frontend only. Just showcasing a pattern I found that improves things on the frontend. As I said previously, it has to be a holistic approach to security and ignoring the frontend because the backend is solid is just as bad as a frontend only approach.
I'm agreeing, not disagreeing.
I can sort of see this being valuable as part of defense in depth, but if that's the only thing preventing secrets being exposed then it's just security through obscurity, which is really no security at all. Secrets should never be included directly in code bundles, if they're present there then something's already gone badly wrong.
I would always advocate for defense-in-depth. In fact, I use the word secrets lightly. I’d rather not have the API endpoints in code, but it’s a necessity. I wrote this article as another layer I realized that might not be used as effectively as it could.
Great perspective!
It’s true that in large SPAs (especially with sensitive dashboards or admin modules), lazy loading can indirectly reduce the attack surface.
I’ve seen some WordPress-based apps using dynamic script injection for similar reasons — might be worth exploring cross-framework patterns like that.
Yes. I think I’ve got a lot of research to do. Thank you for the thoughts.
Thanks for sharing these insightful article.
You’re welcome!
This cover is amazing U w U
Thank you. I can't take too much credit - dozens of attempts at various options (in Canva).
Does lazy loading hide code, or just delay it until auth?
It doesn’t “hide” code. The code is not loaded until proper auth takes place. So, yes, the code is visible and potentially accessible at some point. This is one step in a security fence.
This is a very insightful exploration of using lazy loading beyond just performance optimization, extending it as a layer of security for frontend code.
Thank you. I like how you phrased this!
Very insightful information
Thank you. There's just enough content here for an article; not enough (yet) for a conference talk ...