---
title: "Audit of Your React Application & Safeguarding Your Web App"
canonical_url: "https://www.bigbinary.com/blog/conducting-frontend-security-audit"
markdown_url: "https://www.bigbinary.com/blog/conducting-frontend-security-audit.md"
---

# Audit of Your React Application & Safeguarding Your Web App

- Author: Ajmal Noushad
- Published: August 24, 2023
- Categories: ReactJS

## Introduction

In the realm of web development, securing web applications is paramount to
protect user data and ensure the integrity of the system. Regular frontend
security audits are essential to identify and address vulnerabilities. In this
blog post, we will explore the process of performing a frontend security audit
specifically for React applications. We will highlight key areas to focus on to
enhance the security of your React codebase.

### 1. Verify the usage of dependencies

Begin the frontend security audit by scrutinizing the dependencies used in your
React application. Remove any unused dependencies to minimize potential attack
vectors. Stay updated with the latest security patches and regularly update the
dependencies to mitigate known vulnerabilities.

### 2. Audit dependencies for security vulnerabilities

Leverage tools like `yarn audit` or `npm audit` to scan your dependencies for
any known security vulnerabilities. Stay vigilant in addressing these
vulnerabilities promptly by updating to the latest secure versions or seeking
alternative libraries when necessary.

### 3. Guard against cross-site scripting (XSS)

React is ‘mostly’ safe from XSS attacks. Because under the hood, it has built-in
protection against XSS attacks. React automatically encodes any user input
before rendering it, ensuring that user input is never executed as code. This
feature makes React almost inherently secure in terms of XSS vulnerabilities.

However, we can still choose to render user provided html and scripts through
`dangerouslySetInnerHtml` prop or using libraries like `html-react-parser` or
`html-to-react`. While doing this, we should be very careful to use it only when
It is absolutely necessary to make sure we are sanitizing the raw HTML using a
library like `Dompurify`.

```jsx
import DOMPurify from "dompurify";
import htmlReactParser from "html-react-parser";
import { Parser as HtmlToReactParser } from "html-to-react";

const htmlToReactParser = new HtmlToReactParser();

const UnsafeComponent = userProvidedHtml => {
  return (
    <>
      <div dangerouslySetInnerHTML={{ __html: userProvidedHtml }} />
      <div>{htmlReactParser(userProvidedHtml)}</div>
      <div>{htmlToReactParser.parse(userProvidedHtml)}</div>
    </>
  );
};

const SafeComponent = userProvidedHtml => {
  const sanitizedHtml = DOMPurify.sanitize(userProvidedHtml);

  return (
    <>
      <div dangerouslySetInnerHTML={{ __html: sanitizedHtml }} />
      <div>{htmlReactParser(sanitizedHtml)}</div>
      <div>{htmlToReact(sanitizedHtml)}</div>
    </>
  );
};
```

Another XSS attack surface in React is URLs provided to anchor tags. React
doesn’t escape strings provided as HTML attribute props. So strings like
`javascript:alert(0)` would trigger the JavaScript code when passed to `href`
prop of an anchor tag.

For example the below anchor tag would trigger a browser alert dialog when
clicked.

```jsx
<a href="javascript:alert(0)">Click me</a>
```

Similarly, the code below would also trigger a browser alert dialog.

```js
window.location.href = "javascript:alert(0)";
```

We have to be careful when using links inputted by users to render links or
redirect to them by setting `window.location.href`. To prevent the code from
executing, we can use backend validations to make sure the links are valid and
safe to use. For additional safety we could implement a whitelist of allowed
protocols like `https` and `http` and reject all other protocols on the
frontend.

```js
const getSafeURL = url => {
  const parsed = new URL(url);
  if (parsed.protocol !== "https:" || paresed.protocol !== "http:") return;

  return url;
};
```

Inspect links and redirect logic in your frontend code for potential cross-site
scripting vulnerabilities. Validate user-inputted URLs to prevent unauthorized
execution of malicious code. Implement measures to sanitize and escape
user-generated content properly.

### 4. Verify the necessity of third-party scripts

Examine the 3rd party scripts included in your web application and verify their
necessity. Remove any unused or unnecessary scripts, reducing the attack surface
and potential risks.

### 5. Load assets over secure protocols

Ensure that all assets, such as images, fonts, and stylesheets, and external
scripts are loaded over secure protocols such as `https`. Loading even a single
asset over insecure protocols like `http` can expose your application to
potential security risks, and attackers can exploit this to steal sensitive
information.

### 6. Avoid attaching tokens to external API requests

It is a common practice to have a default header configured for all API requests
in an application. Libraries like `axios` allow us to configure a default header
for all requests. This is useful when we need to attach an authentication token
to all requests. However, this can be a potential security risk if we use the
same axios instance to make requests to external APIs. This is because the
authentication token would be attached to all requests made to external APIs,
which could be exploited by attackers to gain access to sensitive information.

### 7. Always encode URL paths and parameters

It is crucial to consistently encode URL paths and parameters to prevent the
execution of malicious code. Rather than manually encoding URLs each time, it is
recommended to utilize libraries specifically designed for constructing URLs
such as `query-string` or `qs`. By leveraging these library functions, you can
automate the encoding process and ensure that URLs are properly sanitized,
minimizing the risk of security vulnerabilities associated with unencoded or
improperly encoded data.

```js
import qs from "qs";

const params = {
  name: "John Doe",
  age: 25,
};

const encodedParams = qs.stringify(params);
// encodedParams = "name=John%20Doe&age=25"
```

### 8. Enhance script integrity with the "integrity" attribute

To ensure script integrity, add the `integrity` attribute to the available
scripts. This attribute verifies that the script file hasn't been tampered with
and matches the original source. It provides an additional layer of protection
against malicious modifications.

```html
<script
  src="https://example.com/myscript.js"
  integrity="sha384-AbCdIjK..."
></script>
```

### 9. Remove source maps from the production bundle

Source maps are useful during development for debugging purposes, as they map
the minified or transpiled code back to its original source code. However, in a
production environment, making the source code easily accessible through source
maps can pose a security risk. Attackers can analyze the source code to identify
vulnerabilities, potentially exposing sensitive information or gaining insight
into your application's inner workings. By disabling source maps, you reduce the
risk of exposing your codebase to potential attackers. Source maps also provide
an avenue for potential intellectual property theft. Disabling source maps in
the production build helps protect your intellectual property by making it
harder for unauthorized parties to reverse engineer and steal your code.

Disabling sourcemaps would also disable extensions like React Devtools, Redux
Devtools, etc. which could be used by attackers to gain access to sensitive
information.

### 10. Securely manage state

Use proper state management practices in your React application. Avoid storing
sensitive information in component state or global state management systems that
can be accessed or modified by unauthorized users. Utilize techniques like
secure context providers or server-side session management to handle sensitive
data securely.

### 11. Evaluate storage and data handling

Carefully examine the usage of `localStorage`, `globalProps`, and `cookies` in
your frontend code for sensitive data, such as user credentials, authentication
tokens, user locations, API keys and personally identifiable information.
Implement encryption and secure protocols to protect sensitive data where
required.

### 12. Robust error handling

Review your error handling mechanisms to ensure that error messages are
informative but do not divulge sensitive system details or implementation
specifics. Avoid logging or displaying error messages that could potentially aid
attackers in exploiting vulnerabilities, like shown below.

```js
try {
  // Some code that may throw an error
  const userData = await fetchUserData(userId);
} catch (error) {
  console.error("Error occurred while fetching user data:", error);
}
```

Instead, log errors to a secure backend service and display a generic error
message to the user. This would prevent attackers from gaining access to
sensitive information while still providing a good user experience.

```js
try {
  // Some code that may throw an error
  const userData = await fetchUserData(userId);
  // Process the fetched data
} catch (error) {
  // Perform appropriate error handling, such as:
  // - Providing a user-friendly error message with helpful information
  // - Offering options for users to retry the operation
  // - Logging the error to a secure logging service for further analysis
  // - Implementing fallback behavior or graceful recovery if possible

  // Log the error to a secure logging service
  logError(error);

  // Display a user-friendly error message
  toast.error("Oops! Something went wrong. Please try again later.");
}
```

### 13. Enforce eslint rules that prevent unsafe practices

Leverage eslint rules to enforce best practices and prevent unsafe coding
practices. Below are some recommended eslint plugins that can be used to
identify and prevent potential security vulnerabilities in your application.

- [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security)
  Identifies potential security hotspots, such as a dangerous regular
  expression, square bracket notation, etc.

- [eslint-plugin-sonarjs](https://github.com/SonarSource/eslint-plugin-sonarjs)
  SonarJS rules for ESLint to detect bugs and suspicious patterns in your code.

### 14. Implement Content Security Policy (CSP)

Content Security Policy is an HTTP header that helps mitigate various web
vulnerabilities, including cross-site scripting (XSS) attacks. Define a robust
CSP for your web application to specify the trusted sources from which various
resources, such as scripts, stylesheets, or images, can be loaded. This
restricts the execution of untrusted code and helps prevent XSS attacks.

### 15. Regularly review and update security measures

Perform periodic reviews and updates of your frontend security measures. Stay
updated with the latest security best practices, vulnerabilities, and patches.
Continuously monitor security advisories for your dependencies and promptly
address any reported security vulnerabilities by updating to secure versions or
migrating to alternative libraries.

## Conclusion

Conducting a frontend security audit is an essential part of safeguarding your
web application from potential threats. By following the outlined steps and
implementing best practices, you can significantly reduce the risk of security
breaches and protect your users' data and privacy. Remember, staying proactive
in maintaining the security of your frontend codebase is crucial in an
ever-evolving threat landscape.

## Links

- [Human page](https://www.bigbinary.com/blog/conducting-frontend-security-audit)
