
How to Secure Angular.js Applications

Angular.js applications carry more attack surface than most teams realise at the point of initial deployment. This post covers the specific vulnerabilities that matter, the mitigations that actually work, and the trade-offs you'll make along the way.
What Makes AngularJS Applications Specifically Vulnerable?
AngularJS (1.x) has a few characteristics that set it apart from newer frameworks from a security standpoint.
The most significant is its client-side template engine. AngularJS evaluates expressions inside {{ }} in the browser. If user-supplied data reaches the template engine without sanitisation, you get client-side template injection (CSTI), which is effectively remote JavaScript execution in the victim's browser. This is distinct from server-side template injection, but the impact is comparable: full XSS, session hijacking, credential theft.
The second is AngularJS's age. Version 1.x reached end-of-life in December 2021. It no longer receives security patches. Any CVE discovered after that date stays unpatched upstream. If you're still running AngularJS 1.x in production, that's the first fact your threat model needs to account for.
Third, the $sce (Strict Contextual Escaping) service, which is AngularJS's primary XSS defence, is bypassable if you call $sce.trustAsHtml() carelessly. A lot of legacy codebases do exactly that, usually because a developer was trying to render dynamic HTML quickly and didn't appreciate what they were disabling.
How Do You Actually Prevent XSS in an AngularJS App?
Cross-site scripting is the dominant risk. The defences operate at several layers.
Use $sce Correctly
AngularJS's $sce service is on by default. It sanitises values before binding them to the DOM. The problem comes when developers call $sce.trustAsHtml(), $sce.trustAsUrl(), or $sce.trustAsResourceUrl() on values that originate from user input or external APIs. Audit every call to these methods in your codebase. If any of them wraps a variable rather than a hardcoded string, that's a finding.
For rendering user-supplied HTML (e.g., a rich text comment), use the ngSanitize module. It strips dangerous tags and attributes using a whitelist. Install it as a separate dependency (angular-sanitize) and declare it as a module dependency. Do not parse and render raw HTML any other way.
Lock Down Content Security Policy
A well-configured Content Security Policy (CSP) is your second line of defence when something slips through the template engine. For AngularJS applications, the minimum useful CSP looks like:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self';
AngularJS has a CSP-compatible mode. Enable it by adding the ng-csp directive to your root element. Without this, AngularJS uses eval() internally, which requires 'unsafe-eval' in your CSP and largely defeats the purpose.
Test your CSP with Google's CSP Evaluator before shipping.
Expression Sandboxing Is Gone — Plan Around It
AngularJS 1.x used to ship an expression sandbox intended to restrict what could be executed inside template expressions. It was bypassed repeatedly. The sandbox was removed entirely in AngularJS 1.6. If your threat model assumed the sandbox was still present, remove that assumption now.
The practical implication: any user input that reaches a template expression is dangerous. The mitigation is to ensure user data never reaches the Angular expression parser directly. Bind to sanitised model values, not raw inputs.
Authentication, Authorisation, and Token Handling
AngularJS applications are SPAs. The client holds authentication state, which means the client is also a target.
Store JWTs and session tokens in HttpOnly, Secure, SameSite=Strict cookies rather than localStorage or sessionStorage. Tokens in localStorage are readable by any JavaScript on the page, which means any XSS vulnerability becomes a full account takeover. Cookies with HttpOnly cannot be read by JavaScript at all.
Use AngularJS's $http interceptors to attach authentication headers consistently. Centralising this in one interceptor prevents the common mistake of forgetting to attach a token to a specific API call.
For authorisation, enforce it on the server. Route guards in AngularJS ($routeProvider resolve functions or ui-router resolvers) are a UX convenience. They stop the user seeing a page they shouldn't. They do not stop someone with browser developer tools from calling your API directly. Every sensitive API endpoint must validate the caller's permissions server-side, independently of what the client sent.
/// Not sure where to start?
Get the architecture before you commit
Tell us what you're building and we'll map the technical approach, stack, and rough timeline. No cost, no obligation, no sales call required.
What Are the Most Overlooked Vulnerabilities in AngularJS Apps?
Cross-Site Request Forgery
AngularJS has built-in CSRF protection for $http. By default, it reads a cookie named XSRF-TOKEN and attaches its value as a request header X-XSRF-TOKEN. Your server needs to set that cookie and validate that header. This only works for same-origin requests. Verify that your server actually implements the validation; the client side alone does nothing.
Open Redirects
AngularJS applications frequently handle redirects after login. If the redirect destination is taken from a URL parameter (?returnUrl=/dashboard), an attacker can set it to an external URL. Validate redirect destinations against an allowlist of known internal paths before following them.
Dependency Risk
Run npm audit regularly. AngularJS 1.x itself will not receive patches, but your transitive dependencies still receive CVEs. In 2023, several widely-used build-tool dependencies were found to contain high-severity vulnerabilities that had been present for years. Dependency scanning in your CI pipeline is not optional.
Subresource Integrity
If you load any scripts or stylesheets from a CDN, add integrity and crossorigin attributes. Subresource Integrity (SRI) ensures that if the CDN is compromised and the file is modified, the browser refuses to execute it. Generate SRI hashes using the SRI Hash Generator.
Migration vs. Hardening: An Honest Trade-Off
| Factor | Harden AngularJS 1.x | Migrate to Angular 17+ |
|---|---|---|
| Time to production safety | Days to weeks | Months |
| Upstream security patches | None (EOL) | Yes |
| Long-term maintenance cost | High | Lower |
| Risk of introducing regressions | Low | High during migration |
| Team knowledge required | Existing codebase knowledge | Angular 17, RxJS, TypeScript |
If your application is small and undergoing a planned rewrite in the next 6 to 12 months, hardening makes sense as a bridge. If it is large, actively developed, and expected to run for years, the hardening effort compounds indefinitely on an EOL foundation. Migrating to Angular 17 is the honest long-term answer, even though it is painful.
A phased migration using the AngularJS to Angular upgrade module (@angular/upgrade) allows you to run both frameworks simultaneously and migrate component by component. It is not simple, but it is the approach that keeps the application functional throughout.
Conclusion
Securing an AngularJS application means working with a framework that is no longer receiving upstream support. The protections that matter most are correct $sce usage, a strict CSP with ng-csp enabled, HttpOnly cookies for token storage, CSRF validation on the server, and continuous dependency scanning.
Your next concrete step: audit every call to $sce.trustAs* in your codebase this week. That single pass will surface the majority of your highest-severity XSS risks. After that, review your CSP header against Google's CSP Evaluator and address anything rated high or critical.
If you're planning a migration to Angular 17 and want a technical opinion on sequencing and risk, that's a conversation worth having before you commit to a timeline.
FAQ
Is AngularJS still safe to use in 2024? AngularJS 1.x reached end-of-life in December 2021. It receives no security patches. You can harden an AngularJS application significantly, but any CVE discovered in the framework itself after EOL will remain unpatched upstream. For long-running production applications, migration to a maintained framework is the responsible path.
What is the difference between AngularJS and Angular for security purposes? AngularJS (1.x) uses a client-side template engine with an expression parser that has historically been exploited for CSTI attacks. Angular (2+) uses a compiled template model that does not expose an expression parser to the browser at runtime, which eliminates that entire class of vulnerability. Angular also receives active security patches and has a published security policy.
Does enabling CSP fully protect an AngularJS app from XSS?
No. CSP significantly reduces the impact of XSS by blocking inline script execution and restricting script sources, but it is a mitigation, not a prevention. Attackers can sometimes exploit CSP misconfigurations or use allowed script sources to inject malicious code. Input sanitisation and correct $sce usage remain essential.
Should I store JWTs in localStorage or cookies?
Use HttpOnly, Secure, SameSite=Strict cookies. Tokens in localStorage are accessible to any JavaScript on the page. A single XSS vulnerability becomes a full token theft. HttpOnly cookies are invisible to JavaScript entirely, which removes that attack path. The trade-off is that cookies require CSRF protection, which AngularJS's $http supports natively.
How do I test an AngularJS app for client-side template injection?
Start by submitting {{7*7}} into any input field that renders output on the page. If the page displays 49 rather than the literal string, the input is reaching the Angular expression parser unsanitised. From there, use a tool like DOMPurify's test suite or manual payloads to assess the depth of the vulnerability.
Have a project in mind? Contact Sodio Technologies to discuss your requirements and explore the right technology solution for your business.
/// Work with us
Talk to the engineers who'd build it
You'll get a technical scope, timeline and cost estimate from the people doing the work, not an account manager. In-house team, no subcontracting, since 2016.
