Contemporary Single-Page Applications and Frontend Security


The past decade witnessed a meteoric rise in the number of applications adopting the Single-Page Application (SPA) model. Such applications are designed in such a way that the content on every new page within the application appears on a single web page, without having to load new HTML pages. Single-Page Applications leverage JavaScript capabilities to manipulate Document Object Model (DOM) elements, allowing to update all the content on the same page. 

A more traditional web page architecture loads different pages as the user attempts to open a new web page. In this case, each HTML page is usually linked to other pages. Upon each page load, the browser fetches and displays a fresh page.

Whereas, Single-Page Applications are enabled by JavaScript frameworks such as React, Angular, and VueJS. These frameworks help to conceal the complex functions that SPAs perform. They also provide additional benefits such as modular reusable components, state management, etc. Such modern frameworks help SPAs execute web pages effortlessly, as compared to multi-page applications that use Vanilla JavaScript. Using plain JavaScript makes it difficult to keep the UI updated with dynamic state changes. 

The emergence of such frameworks causes changes in the security implications it may have on the frontend. Therefore, it is necessary to understand their internal machinery while disassembling client-side code and how modern frameworks change the attack vectors. 


Build Process

As is customary, a developer creates a web page by defining the page structure in an HTML file and its styling in a CSS file. Then, it is linked in HTML using tags such as <style> or <link>, by embedding JavaScript code with <script> tags. However, building Single-Page Applications is more complicated than this. 

Frameworks such as React and Vuejs provide a virtual DOM, which allows you to steer clear of raw HTML. A virtual DOM, unlike a normal DOM, is a concept in which the representation of the UI is stored in memory, instead of rendering it on the browser with every change. This allows faster changes to DOM. The code is also written in modular JavaScript files which is then processed in the build process.

Here’s a diagram overviewing the build process:


Single-page application build process



JavaScript is a dialect of ECMAScript and it isn’t a fixed standard; new features are added to ECMAScript with newer standards, every few years. While newer standards are released frequently, no browser JavaScript engine (Chromium V8, Safari Javascript Core, Firefox SpiderMonkey) fully implements all the ECMA specifications, each having certain differences in features they support. Also your code needs to be compatible with older browsers released to support older specifications alone.

Transpiling enables you to write modern code which is then converted to standards and features that are supported everywhere, for e.g. ES6 -> ES5. You might use const, let to define your variables but the transpiler helps to convert it to var, internally.

Transpiling is also used to convert code in JavaScript dialects such as Typescript and Coffeescript to plain JavaScript. Each dialect contains its own transpiler such as tsc for Typescript. Babel is the most prevalent transpiler.



A typical modern app contains hundreds of external dependencies when you look at it recursively and it isn’t practical to load each of those separately in a script tag.

Through the process of bundling, you can take each import or require statement, find the source files and bundle them all into one single JavaScript file, applying appropriate scoping.

With the help of this process, all of the code that makes the application work is bundled together; the business logic code as well as the boiler-plate code are bundled together.


Minification/ Obfuscation

The final JavaScript output usually can be very large due to extra spaces or unnecessary, redundant data. Therefore, the final step in the build process is to minify the code. During the process of minification, comments/ whitespaces are removed, identifiers are renamed to shorter variants, and certain routines are simplified. This process then leads to obfuscation, wherein the final code is unreadable and differs highly from the source code.

Bundling and minification is usually done using Webpack.


Single-page application: Original code - easy to read
Original code – easy to read


Single-page application: Transpiled, Bundled, Minified final output - unreadable
Transpiled, Bundled, Minified final output – unreadable


Reverse engineering code

Once the code has been minified in the build process, security researchers will have to de-minify it to study the app. As most of the information such as variable names are lost during the process of minification, there isn’t a straightforward way to do this. However, there are certain tools to aid you in the process such as


This tool uses machine learning to restore minified variable, function names and infer type information. It also formats the code and adds comments.

After this step, you are still left with a bundled code, but the main logic would be readable.

To debundle it into modules, we need to know how Webpack or any other bundler works.



A bundler starts with an entry point file – the root of your application logic – and traces import and require statements. It then builds a dependency graph, module A requires B which requires C and D, and so on. 

If you look through the Webpack chunks after they have been passed through jsnice, you’ll find a lot of calls to “__webpack_require__(<number>).”

__webpack_require__” is similar to the require JavaScript syntax in functionality, except it contains the logic to load modules from the chunks.

The only way to unbundle a bundle is to construct the abstract syntax tree (AST) manually, as there have been attempts to debundle that aren’t maintained anymore.

You could use these resources to study in depth how a bundle file works and to know the internals of Webpack. In this video, Webpack founder Tobias Koppers shows us how bundling is done manually.


Security Tip

Single-page application security

How do these frameworks change attack vectors?

Reduced XSS

React does not render dynamic HTML; it sanitizes content coming from all variables, even if they do not contain dynamic content. Here XSS is all but eradicated unless the developer uses an unsafe function such as dangerouslySetInnerHTML.

In that case, even if you find data reflection you would not be able to insert HTML.



You could use certain gadgets available in Angular to bypass Content Security Policy (CSP) in certain cases.

<img src=”/” ng-on-error=”$event.srcElement.ownerDocument.defaultView.alert($event.srcElement.ownerDocument.domain)”


Here, if CSP is blocking inline scripts but the page is using Angular, you could use the ng-on-error attribute to get Angular to execute the JavaScript. These types of gadgets are often patched but discovered regularly in Vuejs and Angularjs. 


Android apps

What makes Android apps vulnerable to cyberattacks?


An Android app is a software that runs on devices powered by the Android operating system. Android apps are commonly written in Java programming language and compiled to bytecode. These applications are basically Android Package Kits (APK files) that enable the distribution and installation of Android applications. This is similar to how .exe files are used in Windows OS. The second quarter of 2020 registered 2.96 million Android apps in total compared to 2.6 million in 2018 (on Google Play). And in 2018, high risk vulnerabilities were found in 43% Android applications.

An APK file contains the following components:

  • AndroidManifest.xml: which inturn contains details such as the name of the package, description of access rights, as well as that of the API components.
  • res /: A folder that contains app resources, which does not include precompiled application resources.
  • classes.dex: Application code compiled in dex format that are executable by Dalvik virtual machine. 
  • META-INF/: A folder that contains the hashes and signatures of all files. 


Application sandboxing

Unlike Windows, Android runs each of its applications in a sandbox environment. Application sandboxing or containerization limits the environment in which a code can be executed. It intends to protect the app from interacting with external malicious elements. 

The Android operating system is based on the Linux system which uses the Linux kernel. But unlike the Linux system, each Android application is assigned a unique user ID. The system then sets permissions for a particular user ID, permitting that app alone to access certain features. 

Typically, all Android apps have to request permission to access sensitive data such as contacts, SMSs, and cameras . All these system features are restricted with the help of the Permissions API. The application is permitted to access system features only if the user grants access. 


Applications and processes

Although Android applications are written in Java, the class files that contain Java virtual machine instructions (Java bytecode) are converted to Dalvik executable files (.dex files) that contain Dalvik bytecodes, before they are installed.

The kernel that is used by Android OS manages the working of each application on the device, where Dalvik virtual machine runs independent processes or applications under different user IDs.

Android app Kernel


Sandbox escape

Web applications have universal links to interact with other applications, unlike Android apps. 

Android app-to-app communications are limited, however, it is achieved through the following methods:


  • Intents/ Deeplinks


An intent is used to request action from a different application component. It helps to coordinate the activities carried out by different applications. For example, selecting a photo from your gallery to set your WhatsApp display picture. 

Deeplinks are links that direct you to a specific destination from an application. 

Deeplinks is what makes it possible for users to share the link to a Medium article on Twitter. 


  • Binder IPC 


A Binder enables inter-process communication (IPC) within a kernel. It allows processes to manage shared data. Object Linking and Embedding (OLE) by Microsoft is an example of an IPC.


  • Content Providers


Content providers manage the access to the central repository of data. They provide data to external applications. For instance, content providers grant access to applications to use the contacts and SMSs on a device. 

Even though Android applications are typically sandboxed and isolated, limiting app-to-app communications, they can still be abused. 


What goes wrong?

App misconfiguration or the developer’s bad coding practices make Android applications vulnerable to cyber attacks. Listed below are the most common Android application security issues that developers and users come across.


Hardcoded credentials

Hardcoded credentials are basically plain text passwords, API keys, tokens, etc. in the source code. Although it is quite common for Android applications to integrate third party APIs, they may not necessarily be for client-side API calls. When such credentials are exposed in plain text, they form easy targets for password guessing exploits.  

Recently, CSC BHIM app suffered a data breach, exposing 70 lakh user records, due to an unsecured AWS database. Developers had allegedly coded AWS credentials into the app itself. In such cases, a static code analysis can debug the source code before the program is executed.  It exposes any vulnerability within the static source code. This process is also automatable. However, there can be too many false positives. 


Weak Cryptography

Broken cryptography in Android applications uses weak algorithms for encryption and decryption, or implements a strong algorithm in an insecure way. 

The widely used cryptographic hash function MD5 has been found to be vulnerable. Stream cipher RC4 is known for its simplicity and yet was discovered to have multiple vulnerabilities. 

Finding weaker/vulnerable cryptography could be automated through static analysis.


Using a static analyser in APK

Java decompilers decompile the Java bytecode into source Java code. Using such tools, we convert the APK to produce the source code. Even though they might not be the exact code the developer had written, the classes, methods, and the logic would be the same. This reveals hardcoded credentials or other flaws in the code that the developer may have used. 

Most common developer bad coding practice involves custom cryptography which can be broken quite easily.


HTTPS Issues

Transport security is needed when communicating with the server, this is enforced through HTTPS which uses Transport Layer Security (TLS) to encrypt the data. However, several developers inadvertly invalidate this protection. Several apps choose to trust any certificate given without verifying the trust chain. Such code makes through production when developers test the app in a local environment that may have self-signed certificates, they bypass SSL checks intentionally.

SSL verification could be disabled through code such as by establishing a non validating connection through a custom SSLSocketFactory will turn off all SSL validation.

These bypasses could easily be detected through static analysis.


WebView Issue 

WebView is a component powered by a browser engine that lets Android applications open web pages inside the application itself. As browsers are exposed to attacks through intents and deeplinks, it is not safe to open untrusted web pages within the application. 

For instance, a Twitter user found a WebView bug in ArogyaSetu, which exposed internal files on the local database. The WebView was callable by intent and any app installed on the phone was capable of loading the URL in the WebView. An attacker who has control over the WebView can decide what web page should be opened. If JavaScript is enabled, attackers can execute JavaScript code inside the app, to perform malicious activities. 


Insecure storage 

Creating files outside the Android sandbox allows users to view or alter the file content, and this could be a major security concern. Attackers exploit exposed sensitive data or app configuration data stored outside the app sandbox in a format that is readable and writable by any user. 


Component Misconfigurations

  • Exported services and activities: If your app has activities that are exported (meaning they can be called by other apps), and is a malicious app it can gain access to personal and sensitive data. But just because services and activities are exported, it does not mean that it poses security risks. Inspecting the code will also help detect the flaw. 
  • Misconfigured content providers: As mentioned earlier, content providers manage secure access to app data. Misconfigured content providers grant access to external applications without restrictions. 
  • Broadcast receivers: These are Android components that allow you to send and receive system or application events such as a battery low message. Scanning the source code can help you identify what the Broadcast Receiver is capable of or how it is triggered. Attackers can exploit this flaw and send unwanted messages without the users consent. 



Android core security features such as the application sandbox reduces security issues to a significant extent. But from the flaws discussed above, it should be noted that good coding practices also ensure the security of Android apps. Also:

  • Secure the communication between your app and other applications. 
  • Scan for vulnerabilities such as hardcoded credentials or weak cryptography.
  • Store sensitive information within the sandbox/ internal storage.
  • Request for credentials before providing access to the premium content within the app.
  • Use WebView carefully.
  • Scan for component misconfigurations.

Pen-testing IoT Devices for Vulnerabilities


The ‘S’ in IoT

Urban dictionary defines IoT as: an acronym for “Internet of Things”, e.g. everyday objects (such as light bulbs or refrigerators) that can be accessed and possibly controlled via the Internet. The letter ‘s’ in the acronym stands for data and communication security.


Still wondering where the ‘s’ is?

Although the security of IoT devices demands immediate attention, the abundance of these devices has resulted in the lack thereof. There are more than 40 Billion connected devices at present, and every day a significant number of IoT devices are deployed. 

Internet routers, smart TVs, watches, refrigerators, speakers, and security systems such as cameras and home automation devices, are the most common IoT devices. Some of the lesser-known examples are smart vending machine services like BigBasket’s BBInsta, smart electricity meters, bluetooth-activated rental scooters such as Vogo and Bounce, and smart RO water purifiers like DrinkPrime. And most of these devices have already become indispensable parts of our lives. 


Why is it important to secure IoT devices?

The growing demand for smart devices makes it essential to prioritize its security. However, the following reasons are also notable:


1. Prolonged use:

Unlike other technological devices, connected devices are used for a longer period of time – ADSL Broadband routers released in the late 2000s with software components from early 2000s are still alive and online. However, most of these devices  no longer receive security updates.

2. Low attack protection: 

Most connected devices run on low power and low memory, making it impossible to leverage modern defense techniques, especially against memory corruption vulnerabilities such as buffer overflow. Also, users usually find stack protection, ASLR, etc. disabled.

3. Uncharted terrains: 

The security industry’s primary focus is on web/ desktop applications. Thus neglecting the security of a large number of IoT devices. 

How to detect vulnerabilities in IoT devices?

There are multiple ways to detect the vulnerabilities in IoT devices. We will explore:

  • Firmware Analysis
  • Service Exploitation 
  • Hardware Engagement


1. Firmware Analysis

The advantage of this approach is that it does not require the physical presence of the target device. When we discuss the various ways to detect vulnerabilities in connected devices, I will explain how I discovered a remotely exploitable remote code execution vulnerability in a highly distributed internet router.

Firstly, download the latest firmware from the device manufacturer’s website, often found in the support page related to that device. Manufacturers usually provide user guides with instructions for manual software update or in the case of bricked hardware.

The preferred tool for this approach is binwalk. It is an easy-to-use tool to analyze, for reverse engineering, and to extract firmware images. Moreover, it would work on any unknown binary file. It scans for known file-type signatures within the file, and detects filesystems and known compressed stream types.

Here is a demo of running binwalk on TP-Link Archer C5’s firmware, the default router issued by ACT, Bangalore.


It, then, detects three things within the file:

  1. U-Boot – A bootloader often used in embedded devices,
  2. Some compressed data, and 
  3. A Squash FS file system – These are the root filesystem image and data that are mounted on the device. It will contain all the binaries, scripts, and configuration.

This firmware uses squashFS, but there are other file systems used in embedded devices that one could use: []

To extract SquashFS and other files one can use binwalk itself: `binwalk -e firmware_file` or `unsquashfs`. However, based on the filesystem, one might need to download additional tools to extract the image.

Sample output of the tree command on the extracted directory
Sample output of the tree command on the extracted directory

If binwalk fails to identify the filesystem or identifies false positives instead, we can also try manual analysis. We will discuss this, later in the article. Now that we have the code and the binaries that run on the device, we can start testing.


Upon running binwalk on the firmware for JioFI 2, it detects a lot of files directly in plain text, that are not enclosed in a filesystem. Further, open the firmware file in a hex editor and search the first few bytes (also called magic bytes). The file will be identified as an FBF (Flash Binary File).

In the event that this doesn’t work, we shall assess whether the file is encrypted using entropy analysis with `binwalk -E`.

Left: Entropy analysis of JioFi Firmware which contains plaintext files Right: Entropy analysis of a Sony Audio system firmware. Notice the low entropy in the beginning and then very high entropy for the rest of the file, which indicates an unencrypted header part, followed by encrypted contents
Left: Entropy analysis of JioFi Firmware which contains plaintext files
Right: Entropy analysis of a Sony Audio system firmware. Notice the low entropy in the beginning and then very high entropy for the rest of the file, which indicates an unencrypted header part, followed by encrypted contents

The presence of encrypted firmware usually means that proceeding further is difficult. In that case, one could try reverse engineering the header to see if the decryption metadata (key algorithm) is in the header. This is highly unlikely. 

If the required firmware is not available, or it is impossible to extract anything, there are other ways to proceed.


2. Service Exploitation

An IoT device will have a network interface. So, we can fire up nmap and scan the host for open services.

Routers, for example, have an http server with a web interface for configuration, status information, etc. which is an easy target for bugs. 

Sample output of a scan on my previous isp router; what did I say about outdated software being used
Sample output of a scan on my previous isp router; outdated software being used

The most important vulnerability to look for during such black box testing in web ui is command injection. A lot of the Web UI functionality is just a wrapper for internal linux utilities like iptables, ping, traceroute, etc. 

The actions on the web interface are passed to these utilities as normal parameterized shell commands which can lead to command injection if the input is not sanitized. Apart from this, we should also look for unauthenticated action execution or if any of the pages failed to implement auth checks.


Step-by-step illustration

Here is one such injection I found in a large ISP issued router: 

A normal ping request. Notice how the output is the same as a linux ping command output
A normal ping request. Notice how the output is the same as a linux ping command output


Ping request with the ip ` && uname -a`. Command injection!
Ping request with the ip ` && uname -a`. Command injection!

Once a command injection is executed, we shall escalate that into a full shell access. Usually we will be able to find a telnet binary. If we fail to find the binary in the system, we can download one. Subsequently, start a telnet listener such as this: ` && /usr/sbin/utelnetd -l bin/sh -p 2512`.


Then, we explore the processes that are running.

We can find a lot of interesting data here, such as the boa http server, the TR69 server which is used by ISP to remotely configure the routers to perform updates/ customer care, the SIP client for voice calls, PPPd Point-to-point protocol client between the device, and the isp
We can find a lot of interesting data here, such as the boa http server, the TR69 server which is used by ISP to remotely configure the routers to perform updates/ customer care, the SIP client for voice calls, PPPd Point-to-point protocol client between the device, and the isp

All these files and data expand the attack surface. These binaries and their configuration files determine whether they are custom or off-the-shelf tools. We can leverage reverse engineering toolkits like Ghidra to analyse these binaries and ascertain their susceptibility to memory corruption issues such as buffer overflow or logic bugs.

At this point, we can also explore the filesystem for configuration files or conduct a static source code analysis of the web UI backend. The most prized bugs to seek are remotely exploitable pre-auth RCEs. Also, try to find services that listen on the WAN interface and use that to find a bug.

One of the bugs I found, during this process, was a telnet binary listening on the WAN which used a custom executable/ bin/ login which only worked if supplied with a hardcoded password.

hard coded shodanSuch low-hanging vulnerabilities are not very rare. Developers often leave hard-coded backdoor passwords exposed. These are a couple of instances that prove the same:


Command injection bugs are also very common:


When Developers leave default passwords enabled on the devices, hackers don’t even need vulnerabilities to exploit them. Here is a list of cameras left exposed with default passwords set:

Similarly, we can find routers, printers, security systems, etc. with default passwords enabled.


3. Hardware Engagement

Anticipating a failure, to find vulnerabilities in the firmware or any other running services with black box testing, there are other ways to detect vulnerabilities:

3.1 Serial Interface

Most IoT devices run a full linux kernel on an MIPS or ARM powered box. A serial interface is not uncommon on these types of devices. 

Typically, one can find a UART over RS-232 or TTL interface on the chip of the IoT device. An RS-232 interface will have a 9-pin connector, and a TTL interface will have 3-5 pins. The chip, within the outer case, will have instructions regarding the connectors. Use a USB-TTL converter, soldering the connection between the chip and the converter.

A USB-TTL converter. At least three pins RX, TX, VCC should be connected
A USB-TTL converter. At least three pins RX, TX, VCC should be connected

Then, connect to the serial console and use device admin credentials to log in.

Connecting to the serial console
Connecting to the serial console

These interfaces are usually provided by manufacturers to de-brick the device. At the time of booting the device, we have access to additional functionality such as loading firmware over the network.

Once a shell prompt is initiated, we can use techniques discussed previously, for further testing.

3.2 JTAG

In any case, if the device doesn’t run a full fledged OS or the hardware doesn’t provide a serial connection, there is an even lower level approach we could try.

JTAG is another common hardware interface that enables direct communication with the microcontroller on a board. Even though JTAG was initially used by manufacturers to test all the connections on the board, now they are used for low level debugging.

JTAG connection directions are marked on the chip. Otherwise, the spec sheet of the microcontroller/ processor will have details of the same. Solder directly to the JTAG pins on the microcontroller, to access the debugging interface. 

Additional device to connect to the JTAG Interface such as this Exploit-Nano hacker tool
Additional device to connect to the JTAG Interface such as this Exploit-Nano hacker tool
3.3 What can you do with JTAG ?
  • Pause and step through an operation
  • Inspect memory
  • Write bytes directly into memory, 
  • Set break-points
  • Inject code into the process or process memory
  • Dump the contents of the bootloader
  • Bypass logins, and so on


What can hackers do after finding bugs in these devices ?


The Mirai Botnet attack

In 2016, security vulnerabilities in brands of security cameras almost toppled the internet. The Mirai botnet launched 623 Gbps distributed denial-of-service attacks on multiple targets. The traffic originated from thousands of such security cameras. The next year its variant, Mirai Okiru, was launched, targeting Huawei routers.

The proliferation of IoT devices has made it almost impossible to handle the increasing number of attacks they encounter.

Invading privacy

Most smart devices are frequently exploited to encroach on the privacy of its users:

  • Smart speakers are exploited to listen to interactions.
  • Security devices such as CCTV cameras are abused to gain access to sensitive visuals.
  • Vulnerabilities in routers can lead to internet traffic being compromised. Hackers can see the sites visited through plaintext DNS queries. Further, they can perform MiTM attacks and steal credentials or sessions. These vulnerabilities also expose internal devices to the attacker, bypassing the NAT firewall and causing severe damage.