Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Flutter has gained significant traction within FinTech, underscoring the crucial need for robust security measures. The platform’s popularity attracts attention from both app developers and cybercriminals. Flutter’s strong security posture, evidenced by fewer reported vulnerabilities and CVEs, makes it a solid choice for developing sensitive apps.
Flutter is more resilient to decompilation than native apps. Its binary packaging offers better protection of code and hardcoded data, although the number of Flutter-specific reverse engineering tools is increasing rapidly, continually broadening the potential threat landscape (e.g., reFlutter, flutter-spy, blutter).
Despite its advantages, Flutter apps are not immune to common vulnerabilities:
Privileged Access Issues: Rooting and jailbreak concerns remain prevalent.
Dynamic Attacks: Techniques such as hooking frameworks (e.g., Frida, Xposed) pose significant risks.
App Cloning and Repackaging: Unauthorized duplication of apps is a persistent threat.
TLS Pinning Bypass: Critical for defending against man-in-the-middle attacks.
Session Hijacking and App Impersonation: Compromise user sessions and mimic legitimate apps.
Malware: Leveraging app permissions (accessibility misuse, screen sharing, keyloggers, SMS OTP interceptors, etc.) for malicious activities.
Flutter developers must stay informed about security threats and evolving attack vectors across all supported platforms. This demands n-depth expertise and continuous learning, making app security a specialized area within software development.
In the financial sector, regulators mandate the adoption of a range of security techniques, which can be categorized into three primary areas:
Runtime Application Self-Protection (RASP): Implement client-side measures to monitor and react to integrity and environment compromises.
API Protection: Safeguard against app impersonation using tools like Firebase App Check, attestation services, or API protection SDKs such as AppiCrypt.
Anti-Malware: Detects and mitigates risks posed by malicious apps on client devices.
Basic controls can often be implemented using freemium or community-supported tools. However, advanced enterprise-grade protection typically requires custom development or commercial security solutions.
The proliferation of app-to-API end-to-end protection solutions (such as App Attestation, AppiCrypt, and AppCheck) is effectively countering the escalating threats from mobileoriented API abuse. These threats encompass App impersonation techniques such as botnets, password enumeration scripts, data scraping, promotional abuse, fake registrations, and phishing campaigns.
However, due to Flutter’s compiled nature, Static Application Security Testing (SAST) tools have not yet reached the level of sophistication seen in native applications. This presents a challenge in maintaining security parity with other platforms. Conversely, the advent of Software Bill of Materials (SBOM) analysis has simplified the examination of third-party dependencies, thus enhancing the thoroughness and effectiveness of security assessments.
Overall, while there are still areas needing improvement, the strides made in mobile security tools for Flutter demonstrate significant potential in safeguarding against complex and evolving threats.
App issuers should allocate 20% to 25% of development and maintenance budgets to security features. It’s crucial to recognize that due to the dynamic nature of attack vectors and operating system updates, ongoing maintenance costs for security features may be significantly higher than initially estimated.
Proactive security measures are not just beneficial but essential for app protection in today’s dynamic threat environment. Ensuring comprehensive security requires both strategic investment and dedicated expertise.
Written by Sergiy Yakymchuk (CEO at Talsec)
Talsec = Talos + Security
Talos, a remarkable figure in Greek mythology, was a giant bronze automaton, crafted either by Hephaestus or Daedalus. His sole duty was to protect the island of Crete, tirelessly patrolling its shores. Circling the island three times a day, Talos would hurl stones at approaching ships to fend off intruders, symbolizing unwavering vigilance and defense.
In essence, Talos embodies constant protection — just like Talsec’s approach to security.
Happy Cybersecurity Month — stay vigilant, stay secure!
This step-by-step guide outlines best practices for implementing secure data storage in Flutter applications, providing instructions for integration on both iOS and Android.
Imagine you are developing a sales application for a local store. To expedite the purchasing process, the company decides to store users’ credit card data for future transactions. This data will be stored locally on the users’ devices. The crucial question that arises is: how and where to securely store this sensitive data? The answer to this question is what has led us to write this article.
To illustrate the importance of proper storage practices, let’s consider that you developed the feature without adhering to best practices, which led to the leakage of your customers’ credit card data, resulting in the loss of their trust and some lawsuits. Although this is a undesirable scenario, it could become a reality.
In this context, we will explore security concepts related to data storage and present the best practices for managing each available storage method, ensuring that users’ information remains protected against potential threats and vulnerabilities.
What defines secure data? Basically, it is information protected against unauthorized access, theft, corruption, and destruction outside the application’s expected lifecycle.
Although this definition brings with it a huge challenge, this subject has been debated for a long time in computing, and thanks to that, we currently have some concepts that help us better understand how to achieve this security. For this article, I would like to focus on three.
First, we have encryption, which transforms readable information into protected formats, ensuring that only authorized recipients can access and understand the data. Next, we have access controls, which allow applications to manage who is authorized to access the data and how this will occur. This control can be implemented through various components, such as: authentication, authorization, networking, management, and auditing. Finally, there are hardware-based security solutions, which use physical technologies to protect against attacks. This is possible thanks to execution in an isolated hardware environment, which takes place in a secure area within the main processor. A similar process can be done with the Trusted Execution Environment (TEE), or in a dedicated coprocessor, as happens with Apple’s devices that have the so-called Secure Enclave. These concepts will be further explored throughout the article.
Now that we understand what makes data insecure as well as some of the concepts behind data security, let’s take a look at the methods offered to developers that, by default, have a lower level of security and can be considered insecure.
In both operating systems, Android and iOS, applications can create and store files in the internal file system, even though this access is not exposed to the end user in the same way as in desktop systems. Each application has a dedicated storage space, which provides a certain level of isolation between the data of different applications.
The data best suited for this type of storage includes documents, images, and other larger files. For example, video streaming applications often offer the option to download content so that the user can watch offline. These would be excellent candidates for utilizing this storage method.
Another method for storing small amounts of data is by using UserDefaults on iOS and SharedPreferences on Android. Both were developed to store simple data using key-value pairs, consisting of a key of type String and a value limited to the types supported by each platform.
These systems are ideal for saving user preferences, application settings, and other non-sensitive data that needs to persist between sessions. For example, it is common to store the theme selected by the user, the last accessed tab, or configuration options.
In the previously presented storage methods, data is not encrypted by default. This makes it easier to access information on devices with root or jailbreak access, increasing the risk of exposing users’ sensitive data. On non-rooted or non-jailbroken devices, access to the file system is restricted to protect sensitive system files and application data for security purposes. Root or jailbreak permissions allow us to bypass these restrictions and gain full access to these files.
To illustrate the vulnerability of applications to modified devices, I will extract and modify content within a counting application developed with Flutter. In this example, the value of the last count is stored in a text file. It’s important to note that this lack of security is not specific to Flutter — the same issue would occur if the application were developed natively for Android.
For our experiment, it will be necessary to use an emulator with root permissions and the Total Commander application — This will help us access the Android file system. However, it’s worth mentioning that Total Commander is just one of many tools that can be used for this purpose.
The first step is to access our application and add some numbers to the counter. In this way, the application will write and store the count value in a text file.
Next, we will open Total Commander. We will navigate to the data/data/ directory and access the folder named Installed apps. After that, simply locate the counting application we developed.
With that, we will have access to the internal files of our application. To view the created text file, just navigate to app_flutter/counter.txt.
In this way, we can view all the content stored in this file and, in addition, we have the possibility to modify the value as desired. If we change the value, it will be necessary to save the file and reopen the counting application. After this procedure, the modified value will be displayed in the application.
Although we have already discussed data insecurity at length, we have also covered essential fundamentals such as encryption, access control, and hardware-based security solutions. In this section, we will explore storage methods that use these fundamentals to ensure greater data security. However, before we move forward with the content, it will be important to review in more detail the concept of hardware-based security, as this will be crucial to understanding what happens under the hood.
For software to maintain its security, it must rely on hardware that is designed with robust security features. For this reason, Both Android and iOS devices have their own hardware-based security technologies.
In most cases, Android and iOS implement different Hardware-based security solutions. However, they always follow the same principle: creating an environment isolated from the operating system that is secure for performing cryptographic operations. This ensures that even if the main processor is compromised, critical information, such as cryptographic keys and authentication data, like biometric data, remains protected.
On Android, the primary mechanism is the Trusted Execution Environment (TEE), an isolated area within the main processor. However, more recent models are also integrating the Secure Element (SE), a chip separate from the processor and specifically designed for enhanced security.
On iOS, although the Secure Element exists, it is more related to Apple Pay technologies. The primary focus for developers is the Secure Enclave. This hardware component is integrated into the main processor and acts as a coprocessor exclusively focused on security.
I know, all this talk about hardware may seem distant from our reality as app developers. However, have you ever heard of Android's KeyStore or Apple's Keychain?
Tools like the Android's KeyStore and the Apple's Keychain bridge the gap between complex security-dedicated hardware and everyday development. However, these tools differ in how they operate.
The KeyStore present on Android devices is responsible for ensuring the security of the cryptographic keys used. It also allows developers to restrict when and how the keys can be used by applying access control concepts, such as requiring authentication before the data is utilized. As mentioned, the KeyStore system integrates directly with security hardware components to ensure that cryptographic keys are generated, stored, and handled in a secure and isolated environment.
While the KeyStore was designed to store cryptographic keys used by applications, Apple's Keychain is more comprehensive, also handling passwords and other small but sensitive data, such as keys and login tokens. Due to this wider scope, the requirements—and consequently the implementation—differ. The Keychain is implemented using an SQLite database stored in the file system. The security of the stored data is guaranteed by encryption, whose key is stored in the Secure Enclave, ensuring protection through both encryption and dedicated hardware. Additionally, access control policies can be applied to the data, further reinforcing security.
After all this overview on data security in mobile applications, it’s time to show in practice how we can improve the security of the data we store.
Remember the counting app we highlighted at the beginning of the article? Using this, we will demonstrate a step-by-step guide on how to apply the concepts we presented throughout the article.
As mentioned, encrypting is transforming readable information into protected formats. But how does this actually happen? The explanation depends on the type of cryptography: it can be symmetric or asymmetric. In the tutorial below I will only be focusing on symmetric algorithms, if you are curious about asymmetric algorithms feel free to do your own research.
Symmetric encryption algorithms use only one key to encrypt and decrypt data. Their two main advantages are speed and efficiency, which makes them very advantageous for large volumes of data. One of the most well-known symmetric encryption algorithms on the market is AES, and it is precisely the one we will use in our tutorial.
To get started, we will import the encrypt package.
Then, we will add a key property to the CounterStorage
class; this key will be used to encrypt and decrypt our data.
And to generate the key, we can do this using the functions from the encrypt
package.
Next, we will create the encryptData function.
And finally, the decryptData
function.
Now that we have functions capable of encrypting and decrypting data, the following question arises: if the keys in symmetric encryption are unique, and only the key used for the encryption process is capable of decrypting, how will we store the key in a secure way?
Returning to the application we are developing, we will add a new property to the CounterStorage
class.
In addition, we will add one more function: this will be responsible for retrieving from the Keychain or Keystore the key used for encryption, if it exists.
In this way, we have implemented a secure data storage solution that ensures the protection of the stored data. The complete code is as follows:
To boost the security of your applications even more, we have decided to introduce another concept in this article: RASP (Runtime Application Self-Protection). This technology helps us create security strategies based on the context in which the application is running. Through various real-time security checks, RASP can identify changes in the devices used to run the application or modifications to the application itself.
To implement RASP in Flutter applications, we recommend using freeRASP, as it offers a comprehensive range of security checks, including:
Detection of VPN usage;
Identification of developer mode enabled on the device;
Checking for special permissions, such as root or jailbreak;
Detection of execution on simulators;
Verification of installations from unofficial app stores, ensuring the application's legitimate origin;
Additionally, when any security violation is detected, freeRASP allows you to implement countermeasures through a fallback mechanism, ensuring your application responds appropriately to potential threats. It also offers the option to receive weekly security reports via email, providing valuable insights.
In the counter app example, freeRASP could be used to delete any data stored in the application or even close the app upon identifying whether the user's device has root or jailbreak. This would help prevent unauthorized access to the data and ensure that the application runs only on secure devices.
Sensitive data is present in all applications, whether it's credit card information, user tokens, or other types of confidential information. It is important to emphasize that security is an ongoing process. In this article, we explored some security concepts, such as Cryptography, Access Control, Hardware-Based Security, and RASP, and how they assist us on the journey to make our application environments increasingly secure.
As developers, we must always prioritize best practices in data security and stay attentive to the latest updates of our environment and possible vulnerabilities, continuously strengthening the strategies we adopt in our applications.
We encourage you to implement the strategies discussed in this article and to continue delving into topics related to data storage insecurity. If you have comments about this article, we would be happy to receive an email from you.
The following example was adapted directly from Flutter’s official documentation on .
Our goal, therefore, will be to encrypt the file in which we store the information from the counting app. For this, we will use a package known by the Flutter community, . It will provide us with the necessary functions to use the AES algorithm.
One effective solution is to utilize hardware-based security mechanisms, such as Keychain and Android. They will help us store the cryptographic keys we generate for encrypting our files in a secure location. To integrate our counting app with Keychain or KeyStore, we will need a package capable of bridging with these native operating system technologies, and for this task, we chose .
If you are interested in freeRASP and want to learn how to implement it in your applications, we recommend taking a look at the official website of , the company's owner of this project.
A New Play Integrity (former SafetyNet) and DeviceCheck Attestation Alternative
The excellence in mobile security has allowed us to develop a ground-breaking enhancement for mobile API security. Let’s look at the AppiCrypt®, a powerful tool that provides proof of app and device integrity for backends. We will explain common questions about these similar technologies and the application domains they can cover.
There has been a long-standing need to protect APIs against malicious requests and reverse-engineering attempts for the past years. APIs have become an attractive target for cybercriminals trying to seize business assets through information scraping, password brute force attacks, DDoS attacks, MitM attacks, fake accounts, remote code executions, and JSON denial-of-service attacks.
The mobile-first strategy heavily depends on the protection of both the application and API sides. API keys used within your application can be easily retrieved and misused. You need to remember that the mobile application installed on the users’ mobile devices is running in an uncontrolled and untrusted environment. It doesn’t matter whether it’s a renowned device brand like Samsung Galaxy or a EMV POS terminal. There are multiple ways your app may leak secrets.
From the API perspective, all calls must be performed over a secure channel between the client app and the API service. You will primarily utilize HTTPS and TLS in the majority of cases. Static and preferably dynamic certificate pinning (SSL pinning) can be used to provide verification of the backend.
The only thing missing is the verification of the authenticity of the client. The most popular choice (check this awesome write-up) is sending the API key within the requests header. Such authentication is often hardcoded into the clients code. Unfortunately, simple reverse engineering is enough to steal both API keys and client authentication secrets.
Once you acknowledge it is not secure enough, you can defer MitM by using SSL pinning and strengthen your application self-protection by using Runtime Application Self-Protection (RASP) suite like a freeRASP to mitigate more attack vectors from within the App. The device is deeply inspected to determine whether it is rooted, jailbroken, or an emulator. Subsequently, the application is scanned to ensure it hasn’t been tampered with, reverse-engineered, run with debugger or repackaged. Both phases are needed to determine whether the application’s backends are communicating with a legitimate application running on an approved/genuine mobile device.
App authenticity and integrity of the device and the application can be additionally verified by remote attestation services like Play Integrity for Google Play enabled Android phones or DeviceCheck for iOS are good technologies but they have significant drawbacks that we will review later in detail. The good things are that they address API vulnerabilities that WAF and API gateway solutions cannot address as they miss endpoint integrity controls.
An AppiCrypt® is a technique that ensures cryptographic evidence or proof of client App authenticity and integrity. On top of that, it provides device identity with security risk scoring for fraud prevention, enabling more sophisticated techniques like channel binding, device binding to users, step-up authentication, and others.
AppiCrypt® technology is the innovative solution that stands for App Integrity Cryptogram. Thanks to this technology, you can implement the idea of mobile endpoint protection in the concept of zero trust. AppiCrypt is the cryptographic integrity proof of both mobile OS and App that can help prevent mobile API abuse and eliminate the intrinsic weakness of standalone RASP protection.
Generally speaking, the RASP is always just mitigation of Reverse Engineering risk by making the attacker’s job more difficult. Conceptually, the attacker can cut off the RASP part from the app by tampering. So it depends mainly on the attackers’ experience, efforts, and resources available to break the RASP protection.
AppiCrypt solves similar problems as device attestation services like Play Integrity and DeviceCheck. In contrast to such attestation solutions, it doesn’t depend on external web services and doesn’t introduce any outage risk due to external party service unavailability. AppiCrypt solves significant security problems with minimum integration efforts on both application and backend sides.
The idea behind this technology is not just to protect API against attackers trying to impersonate legit App calls but also to let your backend know that RASP controls were overcome or turned off by attackers. So gateway can easily block the session if the App integrity is compromised, and only
in the case that RASP control passed API calls can be processed by backends. Moreover, AppiCrypt is enhanced with fine-grained application security intelligence for backends (like UI overlays, accessibility service usage, etc. ).
You’ve most probably heard about Google Play Integrity. Google’s attestation tool got quite popular because it is preinstalled on common devices equipped with Google Mobile Services. Like the AppiCrypt, it helps determine the overall integrity of the device. Make no mistake. Play Integrity, nor AppiCrypt, cannot replace proper Security Development Lifecycle (SDL), and both serve as additional security layers.
Play Integrity’s attestation information provides generalized binary conclusions about the device’s eligibility. The two checks are Basic integrity (“basicIntegrity”: true/false) and CTS profile match check based on (“ctsProfileMatch”: true/false). Yet the second one is only relevant to devices that have been Google-certified. Unfortunately, this gives no clue if you want to support specific platforms (i.e., EMV POS Terminal) or use-cases (i.e., Gaming Emulators) that Google considers inappropriate. The thing is, many users use unlocked devices because they are cheaper to get from 3rd party resellers, so you can’t rely on Play Integrity’s boolean result. Keep in mind that many devices (i.e., affordable Xiaomi models) are shipped with GMS but didn’t pass Google certification. Finally, it gives no threat signals also.
It works only if Google Play Services and good network connectivity are available.
Downtimes may occure time-to-time (see figure below)
It has a high response time caused by network latency and processing time
Play Integrity Attestation fails under many conditions based on network, quota, and other transient problems.
You need to implement verification of the Play Integrity’s result on your backend.
It doesn’t involve many checks (i.e., tapjacking, accessibility service abuse, screen lock status)
Google has no security process to ensure that an OEM ROM is clean. Hence, Play Integrity won’t guarantee you the safety of OEM ROM.
Universal across all platforms (Android with or without Google Services, iOS, Flutter)
Verification serverless component ready to use (i.e., AWS lambda authorizer)
Suited for demanding business (Fin-Tech, Healthcare, Gaming, Government)
Fine-grained threat signals
Reaction based on device identifiers, GPS emulation status, and screen lock status
Attestation even in lousy network connection without quota issues and other transient problems
Supports devices with an unlocked bootloader
Supports devices with a custom system ROMs
Supports devices for which the manufactured didn’t apply for, or pass, Google certification
Supports devices with a system image built directly from the Android Open Source Program source files.
Low latency
Zero dependencies on Google servers middleware means no single point of failure.
Free quota allotment (per project) for calling the Play Integrity Attestation API is 10,000 requests per day and five requests per minute.
Developed and supported by the official Android team
Checks verified boot
The true strength of AppiCrypt lies in its ability to protect multiple application domains. Be it an iPhone, iPad, Amazon Fire Tablet, EMV POS Terminal, or Kiosk, you can use the same AppiCrypt and its backend component. If you need protection in every possible environment, the AppiCrypt is right for you.
To be fair, the Play Integrity also has some advantages over AppiCrypt. Play Integrity’s deep system integration allows for boot integrity checks thanks to better access to the trusted execution environment (TEE). After all, it’s developed directly by the Android team.
Virtually every Android device
iOS (iPhone, iPad)
Flutter apps
Huawei & Honor Devices since Huawei lost Google
EMV POS Terminals
Performance Critical Apps
Amazon Fire Tablets
Self-service Tablets
Kiosks
Gaming Emulators
Non-Google Areas (China)
Devices with custom ROMs
AppiCrypt is courtesy of Talsec. If you are looking for a solution tailored to your specific needs, contact us at https://talsec.app. We provide enhanced RASP protection with malware detection and detailed configurable threat reactions, immediate alerts, and penetration testing of your product to our commercial customers with a self-hosted cloud platform. To get the most advanced protection compliant with PSD2 RT and eIDAS and support from our experts, contact us via https://talsec.app/contact. written by Tomáš Soukal, Mobile Dev and Security Consultant at Talsec
https://talsec.app | info@talsec.app | Read also 5 Things John Learned Fighting Hackers of His App — A must-read for PM’s and CISO’s
The updates in the OWASP Mobile Application Standard (MAS) for 2025 will incorporate a new MASWE called "RASP Techniques Not Implemented." Let us preview the contributed draft written by Talsec
RASP (Runtime Application Self-Protection) encompasses techniques such as root or jailbreak detection, unauthorised code or code execution, malware detection, system state, data logging and data flow. It provides a systematic, organised management approach to securing mobile applications in real time from potential threats.
Ensure that the application flow remains secure and untampered at all times.
Enable applications to detect and trigger responses to threats, such as:
Warning the user.
Killing the app.
Locking access to certain features.
Without RASP implementation, applications remain vulnerable to attacks during runtime. RASP techniques assure that the app continuously monitors both its own state and the device environment to detect threats like malware, root, or integrity issues.
Independent decoupled protection updates.
Remote configuration of security rules.
Threat intelligence gathering.
Fast security incident remediation.
Providing data for security analysis.
Speed and timing of checks is also important and crucial for response times and ensuring no gaps in detection rounds, with control timing checking sensitive steps in the app. Incorporating RASP into an app ensures continuous protection from threats, ultimately minimising risk and improving overall security.
Mobile app security and user security can be disrupted in various scenarios, including:
The application does not comprehensively process information and fails to account for system weaknesses or its own vulnerabilities, potentially leading to breached environment integrity.
Direct reactions to detected threads are not properly executed or integrated into the application’s business logic.
Security rules cannot be effectively defined based on discovered weaknesses, as this approach lacks the broader perspective needed to address all potential threats and ensure comprehensive protection.
Loss of Control and Monitoring: One of the key advantages of RASP is the ability to continuously control and monitor the mobile app’s state and the device environment in real-time. Without these features, the application may fail to detect or respond to unauthorised modifications, malware presence, or tampering attempts.
Missed Threat Intelligence: Without continuous monitoring, security checks, and data logging, we lose a critical overview of potential threats, making it harder to identify emerging attack patterns and respond to malicious activities effectively.
Loss of Manageability and Updateability of Detection Techniques: Without RASP, applications lose the ability to update security rulesets, reset policies/settings, and adjust risk scoring in older or already released apps.
To enhance the security of your mobile application, implement detection mechanisms that continuously monitor the app's state and device environment.
Implement response actions for detected threats to mitigate potential risks, such as:
Killing the app,
Warning the user,
Logging information about potential risks to the database.
RASP (Runtime Application Self-Protection) is designed to monitor and protect the application during runtime by detecting and responding to threats in real-time. The test verifies if the application can identify and react to malicious modifications, such as code tampering, root or jailbreak environment, and attempts to bypass security mechanisms. It also checks if the application has the ability to protect sensitive data and prevent unauthorised access to critical operations or features.
By conducting this test, we ensure that the app is capable of defending against runtime attacks and maintaining its integrity even in compromised environments. If RASP techniques are not implemented or are improperly configured, the app may be vulnerable to various security threats, including data breaches, unauthorised access, and malicious modifications.
Ensure that all security checks and protection mechanisms expected from RASP are present and enabled with the application. To test the RASP policy that the app enforces, a written copy of the policy must be provided. The policy should define available checks and their enforcement. For example:
Root detection.
Screen lock enforcement.
Code integrity checks.
Detection of dynamic analysis.
Based on the previous step, attempt to simulate threats to test if the application reacts as expected. This can involve various scenarios such as:
Launching the mobile application on a rooted device.
Launching the mobile application on a device without a screen lock enabled.
Attempting to repackage the application and launching it.
Launching the application in an emulator.
Verify that the application properly detects and responds to potential threats. There are various scenarios in which a mobile application can respond to these threats, such as:
Killing the app.
Warning the user about the detected threat.
Logging information about potential risks to a database or SIEM.
The output depends on the specific reactions set up for the mobile application. The results should demonstrate the app’s behaviour when a threat is detected or triggered, for example:
Application is terminated.
Application displays a warning message.
Application sends information to a database or SIEM. Testers should ensure that the collected threat intelligence data are rich enough.
The test case fails if the mobile application does not react as expected to the detected threats.
written by Martin Žigrai, Tomáš Soukal
At Talsec, we believe apps should have the option to detect risky environments, including suspicious malware, to ensure no sensitive information is leaked. Let us introduce our advanced in-app malware protection!
https://docs.talsec.app/freemalwaredetection
Known malware
Ongoing malware campaigns
Counterfeit app clones
Tapjacking
Accessibility Screen readers
Other potentially risky apps
Scanning the device for blocklisted apps
Identifying apps installed from untrusted app stores
Detecting side-loaded apps from unverified sources
Apps requiring risky permissions
Any unwanted findings are reported back to the app
All findings are logged for further analysis and tracking
https://docs.talsec.app/freemalwaredetection
Written by Tomáš Soukal — Security Consultant
System VPNs may be used to mask illicit activities, evade compliance controls, or access services from unauthorized regions.
Detecting a running VPN service on mobile devices is critical for security-sensitive applications, as it can indicate potential privacy and security risks. VPNs can obscure the user’s actual IP address and route data through servers potentially under external control, which might interfere with geographical restrictions and bypass network security settings intended to protect data integrity and confidentiality.
Such anonymizing features could be exploited to mask illicit activities, evade compliance controls, or access services from unauthorized regions. FreeRASP checks whether the system VPN is enabled.
Enjoy the ultimate threat modeling knowledge sharing refined through insights from hundreds of sessions with mobile security experts and shared with many CTOs, CISOs, and senior mobile developers who develop for Android, iOS, React Native, and Flutter.
It's ideal for team training workshops as a practical guide to better securing mobile apps and backend APIs, offering actionable insights.
Threat Modeling
TOFU (Trust On First Use)
App and Device Enrollment
Detection, Monitoring, and Security
It focuses on the most exploitable threat vectors, including
Session Hijacking,
Token Hijacking,
Rooting and Jailbreaking (Magisk),
App Impersonation,
App Tampering,
App Cloning,
App Repackaging,
Dynamic Hooking (Frida),
Reverse Engineering and respective prevention and remediation approaches like a RASP.
presented by Tomas Soukal.
While there are multiple options when it comes to choosing a library that implements secure storage in React Native, it is crucial to ensure that the data are stored properly and ideally without any known vulnerabilities. At Talsec, we made an effort to go through the most popular packages, so you can get an image of what is on offer.
This article assumes you are familiar with:
How data storage works on native platforms
Recently, the Talsec team started to support React Native by providing the freeRASP and RASP+ SDKs. We are currently exploring ways how we could go even further and are considering to add a secure storage solution that would follow the latest security standards. In order to proceed, we evaluated the existing secure storage options within React Native and seek input from the community to understand your expectations regarding this feature.
We would love to share our findings so far with a brief description of various secure storage packages available for React Native, along with their benefits and potential vulnerabilities:
✅ Pros: This is a popular package that securely stores sensitive information using the Keychain on iOS and the Keystore on Android. It encrypts data and provides secure storage for confidential data.
⛔️ Cons: While react-native-keychain provides secure storage, it is not immune to all vulnerabilities. The package stores sensitive information, e.g. username and password in clear text in the keychain file, and you can find several concerning issues that are open on GitHub, mentioning that the data from iOS keychain can be retrieved. On top of that, it can only store username/password combination.
✅ Pros: react-native-encrypted-storage is another third-party library that offers secure storage for sensitive data. It uses EncryptedSharedPreferences on Android and Keychain on iOS, encrypts data using AES-256 encryption, providing an extra layer of security.
⛔️ Cons: There are some memory leaks detected by Xcode profiler and Keychain is not cleared when your app is uninstalled on iOS — this issue, however, is well documented and can be fixed.
✅ Pros: rn-secure-storage encrypts data using AES-256 encryption and securely stores it on the device. Plus, it can store any [key, value] pair.
⛔️ Cons: The implementation uses secure-preferences package to store the data, which is nowadays deprecated and it is encouraged to use EncryptedSharedPreferences from androidx.security instead.
Okay, this package doesn’t implement any kind of secure storage and is not intended to store any sensitive data. However, it is still a popular solution for data storage in React Native, prompting us to mention it in this article as well.
✅ Pros: Offers a simple asynchronous storage. It is built on top of the original React Native’s AsyncStorage and provides a convenient API for storing and retrieving data.
⛔️ Cons: The package requires devs to handle encryption of the data on their own, as it stores data in plain text, making it vulnerable to unauthorized access if the device is compromised. We would suggest to avoid using AsyncStorage for sensitive information like passwords or authentication tokens.
Although many devices offer hardware-backed keystores, there is a significant number that lacks it. Moreover, certain devices, particularly those running on Android, face challenges with hardware-backed keystores due to manufacturer-provided software. These implementations either fail to function properly or resort to software-backed alternatives. I suggest checking out the list of public resources related to Trusted Execution Environment (TEE). This resource compilation provides valuable information on reverse-engineering techniques and strategies for achieving trusted code execution on ARM devices.
Another important consideration is that although hardware-backed keystores may provide better protection against key extraction, they are still susceptible to runtime attacks, just like software-backed keystores. During runtime, attackers can still access encrypted data stored in the keystore using rooted devices, a repackaged or tampered app, or hooking frameworks.
Therefore, we have concluded that the most effective approach which will mitigate the risk of runtime attacks is a combination of secure storage with RASP-based solution.
By integrating a software-backed keystore into the RASP (Runtime Application Self-Protection) solutions, we can address two critical aspects simultaneously:
Reliability: The enhanced RASP solution will offer a dependable keystore mechanism that does not rely on secure hardware. This ensures the integrity and protection of cryptographic keys, even on devices that lack hardware-backed security features.
Security: While the keystore itself remains vulnerable to threats like root access and runtime hooks, a closely integrated keystore within RASP can mitigate these risks. It can dynamically determine whether to store or retrieve data based on the current security state of the device.
Through the integration of a software-backed keystore, the enhanced RASP solution provides a comprehensive and reliable approach to data protection, overcoming limitations related to hardware availability and compromised devices.
We hope this summary helps you make an informed decision when considering a secure storage option for your React Native project. But also, we’d be happy to hear your opinion. Would you use a software-based secure storage SDK for React Native that utilizes a hardcoded obscured encryption key?
Please share your experiences, suggestions, and any other secure storage tips. Let’s discuss in the comments below! 👇
Happy coding.
written by Tomas Psota, developer at Talsec
Dive into our full guide as Himesh Panchal walks you through creating a robust and secure authentication flow!
Authentication vulnerabilities remain one of the most critical security concerns in mobile application development. When building Flutter applications, developers often overlook crucial security aspects while integrating third-party authentication providers.
The combined total of apps in the Apple App Store and Google Play Store has surpassed 6 million, but a startling 75% of these apps have at least one security flaw, highlighting the widespread vulnerability in mobile app ecosystems.
Mobile authentication attacks have evolved beyond simple credential theft. Modern attack vectors target the entire authentication flow, from initial user input to session management. A compromised authentication system doesn't just expose user credentials - it potentially compromises your entire API surface area.
Consider this scenario: An attacker extracts an improperly stored refresh token from a jailbroken device. Even with perfect password security and MFA implementation, this single vulnerability allows indefinite API access through token refresh mechanisms.
While providers like Firebase, Supabase, and Auth0 implement encryption to safeguard user data. providers manage backend security, developers must ensure secure practices in their apps to eliminate vulnerabilities. The post will provide actionable insights on encryption, secure token storage, and robust communication strategies for Flutter apps.
The authentication flow in a Flutter application represents a complex sequence of security-critical operations. Each step presents unique vulnerabilities that malicious actors can exploit. Let's analyse the complete flow, focusing on security implications at each stage.
Launch the App: The app initializes and prepares the login screen. At this stage, failing to sanitize inputs or enforce app integrity checks could expose the app to tampering.
Input Validation: Users enter their credentials. Weak validation can allow injection attacks or malformed inputs.
Initiate Login Request: The app sends credentials to the server. Without secure communication channels, credentials may be intercepted.
Receive Authentication Response: A successful response contains tokens; insecure handling can lead to theft or misuse.
Token Management: Tokens need secure storage and monitoring for expiration. Improper storage can lead to credential exposure.
API Calls and Logout: Valid tokens allow API access, while the logout process ensures no lingering session data exists.
JWT (JSON Web Tokens) is a compact, URL-safe way to securely transmit information between two parties as a JSON object. It’s commonly used for authentication and information exchange. A JWT is composed of three parts:
Header: Specifies the token type (JWT) and the signing algorithm (e.g., HS256).
Payload: Contains the claims (data like user info or permissions). Claims can be public, private, or registered (e.g., iss, exp).
Signature: Ensures the token’s integrity using the header, payload, and a secret or public/private key.
JWTs are signed, not encrypted, making them verifiable but not inherently confidential. They’re ideal for stateless authentication and are often used in APIs, enabling secure communication without server-side storage.
JSON Web Tokens form the backbone of modern authentication systems. Their structure requires careful handling and validation:
Before we dive into the implementation, let's set up our project with the necessary dependencies. Add these to your pubspec.yaml
:
The Security Service acts as your application's first line of defense. It continuously monitors the device environment and enforces security policies. This service helps protect your app against:
Device Tampering: Detects rooted (Android) or jailbroken (iOS) devices
Development Tools: Identifies debugging attempts and emulator usage
Runtime Threats: Monitors for malicious hooks and code modifications
Brute Force Attacks: Implements rate limiting to prevent repeated login attempts
The service uses freeRASP for device integrity checks and maintains an in-memory store of failed login attempts. When security violations are detected, it notifies the UI layer to take appropriate action.
The security service monitors device integrity and manages rate limiting. Create lib/services/security_service.dart
:
Why Secure Token Storage Matters
Authentication tokens are like digital keys to your application. Without proper lifecycle management, these keys could become a security liability. Let's understand why token management is crucial and how we've implemented it.
Understanding the Risks
If an attacker obtains a token stored in plain text or one that never expires, they could potentially access a user's account indefinitely. Additionally, without proper refresh mechanisms, users might experience frequent, frustrating logouts.
Here's how tokens are often stored insecurely using SharedPreferences:
Easy Extraction:
On rooted/jailbroken devices, attackers can directly read SharedPreferences files
Tokens are stored in plain text at /data/data/your.package.name/shared_prefs/your_prefs.xml
Example Attack Scenario:
Now that we understand the risks, let's implement a secure solution using flutter_secure_storage
The Token Service handles the secure storage and lifecycle management of authentication tokens. It's designed to:
Secure Storage: Use platform-specific encryption (EncryptedSharedPreferences for Android, Keychain for iOS)
Auto-Refresh: Proactively refresh tokens before expiration to maintain session continuity
Clean Lifecycle: Properly handle token storage, updates, and deletion
Error Recovery: Implement fallback mechanisms for token refresh failures
This service ensures that sensitive authentication data is never exposed in plain text and maintains secure session state across app launches.
Create lib/services/token_service.dart
for secure token storage:
This service integrates Supabase authentication with our security layers. It implements:
PKCE Flow: Uses Proof Key for Code Exchange for enhanced security
Session Management: Maintains and validates authentication state
Token Handling: Coordinates with TokenService for secure storage
Error Management: Provides structured error handling for auth operations
State Recovery: Implements session recovery after app restarts
The service acts as a bridge between Supabase's authentication system and our custom security implementations.
Create lib/services/supabase_auth_service.dart
:
Create lib/screens/login_screen.dart
:
The initialization phase is crucial as it sets up the security foundation for your entire application. This phase orchestrates the proper setup and interaction of all security components.
Update your lib/main.dart
:
While our project uses Supabase's built-in networking, lot of Flutter applications use Dio for HTTP communications. Let's explore how to implement secure networking with Dio.
Imagine sending a postcard versus a sealed letter. HTTP is like a postcard - anyone handling it can read its contents.
Authentication testing is crucial for ensuring your security measures work as intended. Our testing approach combines mock generation with comprehensive test scenarios to verify authentication flows, error handling, and security constraints.
Setting Up Authentication Tests
To implement our tests, we need two key files:
auth_test.dart: Contains our test scenarios and implementations
auth_test.mocks.dart: Auto-generated mocks for simulating authentication services
First, ensure you have the required dependencies in your pubspec.yaml
:
Complete Test Implementation
In our testing setup, we leverage Mockito's powerful code generation capabilities to create mock services. By adding the @GenerateMocks([SupabaseAuthService])
annotation to our test file, we tell Mockito which classes need to be mocked. When we run flutter pub run build_runner build
, Mockito automatically generates auth_test.mocks.dart
, which contains a sophisticated mock implementation of our SupabaseAuthService.
The combination of mock generation and comprehensive test scenarios provides confidence in our authentication system's reliability and security.
Multi-Factor Authentication strengthens your application's security by requiring multiple forms of verification. Think of it as adding multiple locks to your front door – each additional layer makes unauthorized access significantly more difficult.
MFA relies on a combination of:
Knowledge factors (something you know) • Passwords • PIN codes • Security questions
Possession factors (something you have) • Mobile devices • Security tokens • Authentication apps
Inherence factors (something you are) • Fingerprints • Face recognition • Voice patterns
Popular MFA Methods
Time-based One-Time Passwords (TOTP)
TOTP enhances security through authenticator apps that generate temporary codes using time-synchronized algorithms. These codes automatically expire after 30 seconds, providing a secure yet convenient authentication method. The time-sensitive nature ensures that intercepted codes quickly become useless, making it an effective choice for applications requiring strong security.
SMS and Email Verification
SMS and email verification offer familiar authentication experiences using existing communication channels. While simple to implement and widely accessible, these methods are considered less secure due to potential vulnerabilities like SIM swapping or email compromise. They remain popular for applications where user convenience takes priority over maximum security measures.
Building secure authentication in Flutter requires a careful balance between security and user experience. Throughout this guide, we've explored implementing a authentication system that protects user data without compromising usability.
While our implementation provides a solid foundation for secure authentication, remember that security is not a one-time implementation. Regular reviews and updates of your security measures are essential to maintain strong protection for your users.
The principles and patterns we've discussed serve as a starting point. Your specific application may require additional security measures depending on your use case, user base, and sensitivity of data.
Keep building secure applications, stay informed about emerging security threats, and always prioritise your users' data protection.
written by Himesh Panchal
⚡Key takeaways:
Promo abuse is a type of fraud where bad actors take advantage of a business’s sign-up bonuses, referrals, coupons, or promotions.
MediaDRM should be preferred over device fingerprinting whenever possible.
Ultimately, our research suggests the best device ID suitable for blocklisting is a combination of MediaDRM+device model.
Keep in mind that your specific scenario may require a different approach. Drop a message at info@talsec.app, and Talsec security experts will help you.
Recently, we’ve faced a challenge in mobile device identification — how to identify and blocklist a fraudulent device without compromising user privacy. This issue holds particular significance for mobile application owners who frequently contend with users evading payments or exploiting various bonuses.
While it’s common to attract users with enticing bonuses during their initial sign-up, it’s crucial to recognize that this strategy comes with inherent risks and is prone to abuse. These malicious users go to the extent of reinstalling the app multiple times, attempting to gain sign-up bonuses repeatedly — a behavior we term “multi-instancing.”
Since Android alters some device IDs for each new app instance, pinpointing the same bad actor’s device becomes challenging for blocklisting. This underscores the complexity of our pursuit for an effective solution.
In the past, you could identify a device by its MAC address or IMEI without requesting special permissions. Today, after many Android privacy-oriented changes, several semi-persistent IDs are available on Android devices, such as AndroidID, MediaDRM, GSF ID, FID, and InstanceID. Of course, asking users for any permissions with elevated access and potential security implications is unrealistic.
Each of the IDs has its ups and downs, making them useful in different scenarios; see the example table below. You can find additional information about the IDs in the Android documentation.
Alternatively, the ID can be constructed by various device fingerprint libraries (e.g., fingerprintjs-android) based on multiple device IDs, device states, OS fingerprints, or installed apps.
Let’s look closer at these IDs.
While these identification methods may serve well in other contexts, in our scenario, they lack the resilience needed to withstand fraudulent multi-instancing. These IDs are relatively easy to change, so only a quick explanation about downsides of each respective one:
AndroidID changes in case of repackaging or if installed under another user on device
GSF ID (Google Play Service Framework ID) is restricted to Google devices only and can be relatively easily spoofed by XPrivacyLua. It also changes for different users.
FID (Firebase installation ID) won’t survive reinstallation
InstanceID (GUID, UUID.randomUUID().toString()
) is custom generated and internally stored ID, but it won’t survive reinstallation
Google Advertising ID is not suitable at all
In summary, none of those IDs is solid enough to identify bad actors in our scenario.
Notice: In the whole analysis, we worked with the fingerprintjs-android library that uses a comprehensive list of signals for stateless offline fingerprinting. The results of other fingerprinting libraries may be different. They may include more signals and heuristics based on their data insights, geolocation, IP location, TEE, and possibly other magic. Talsec collects fingerprintjs-android V3 & StabilityLevel.OPTIMAL. Differences between stability levels (STABLE — OPTIMAL — UNIQUE) can be found here.
Glance over the table above once again. At first sight, the Hardware Fingerprint (see the table above) could be the best option — it survives anything except for the Instant App event. However, there is one serious drawback to this ID — the collisions. Collisions are caused by the way the ID is calculated — as the name suggests, the ID is solely based on the device’s hardware. Imagine all the Samsung Galaxy Z Flips coming straight out of the assembly line. All of them will have the same ID in case of hardware-based fingerprint. This type of fingerprint is called a STABLE fingerprint.
On the other end, there is a UNIQUE fingerprint, which uses a considerable amount of signals to calculate the device’s ID. IDs created in this way have a high probability of matching only to one user (minimal number of collisions), but because of the high amount of signals, the ID changes quite often (e.g., with some change in settings), making one user have many IDs (making it useless in our use case). Example: ID may change if there is a change in installed apps or Data Roaming is enabled/disabled.
A third type of fingerprint is a compromise between the STABLE and UNIQUE fingerprints — an OPTIMAL fingerprint. It is less stable but more unique than the STABLE one and is collected by the Talsec SDK. But even this type of fingerprint is not as optimal as it sounds — as shown later in this article. Example: ID may change if the user switches between 12 and 24-hour clock representation or Development Settings or ADB is enabled/disabled.
Fingerprint example: `f37fc958dc6d566a8f4bf1e0fd25b510`
MediaDrm is an Android API enabling the secure provision of encryption keys to MediaCodec for premium content playback. It uses DRM providers like Google’s Widevine and Microsoft’s PlayReady. During initial DRM use, device provisioning obtains a unique certificate stored in the device’s DRM service.
Not only is the MediaDRM provided by this API the same for all users on the device, but in our scenario, it’s harder to spoof and can survive many attacks. No permissions are required to get this ID.
Yet, it still has limitations. It may be missing on devices that don’t support MediaDrm. Also, MediaDRM seems to have quite a few collisions with devices of the same manufacturer, as we show further.
MediaDRM example: `e3af1aa4dacb6b6637846488b511e7643c6ac20b65c95baad164b122ecb036b6`
We tested five devices and emulators under multiple multi-instancing scenarios and checked whether the IDs changed or remained the same. The most interesting ones are MediaDRM and Fingerprint (V3 & V5 Optimal), so we especially paid attention to these.
Multi-instancing scenarios:
First install of the app
Reinstall of app
Install in Work Profile
Make a clone of the app using Island App
Make a clone of the app using Parallel Space
Make a clone of the app using Parallel Apps
Make a clone of the app using Second Space (Xiaomi)
Installation in Guest Profile
Factory reset
Android emulator vs. actual device
This tedious work was made easier thanks to a great Fingerprint OSS Demo tool.
Here are the most important observations. Not all tests could always be performed, so we did all the low-hanging fruit ones — essentially, those attackers would attempt also.
Remained the same (= good):
MediaDRM remained the same for the First install, and Island App on the OnePlus 8 Pro
MediaDRM remained the same for the First install and Second Space on Redmi Note 10 Pro
MediaDRM remained the same after the Factory reset on the OnePlus 8 Pro
MediaDRM remained the same for First install, Work Profile, and Multiple Users on the OnePlus 8T
Fingerprint V5 Optimal remained the same for the First install and Parallel Space on the OnePlus 8T
MediaDRM and Fingerprint V3 & V5 Optimal remained the same after Reinstall on Redmi Note 10 Pro
Fingerprint V5 Optimal remained the same after reinstalling for First install, Work Profile, and Parallel Space on OnePlus 8T
Changed (= bad):
Fingerprint V5 Optimal changed for First install and Island App
Fingerprint V5 Optimal changed after a Factory reset on the OnePlus 8 Pro
Fingerprint V5 Optimal changed in Second Space on Redmi Note 10 Pro
MediaDRM changed in Parallel Space on the OnePlus 8T
Fingerprint V5 Optimal changed in Work Profile and Guest User on OnePlus 8T
Other:
FingerprintV3 Optimal was better than Fingerprint V5 Optimal for the emulator
MediaDRM was different on Emulator 1 and Emulator 2 (both on the same Windows machine)
Based on the observations, Fingerprint V3 and V5 Optimal failed in many multi-instance fraud scenarios compared to MediaDRM. From these tests, we can conclude that MediaDRM is the better one.
To quantify the results, we took our data, evaluated the behavior of those IDs, and came up with the most suitable ID based on the data. Remember that our data may be skewed and not representative compared to the devices of your user base.
We took two weeks of our freeRASP data and analyzed them. As the period is relatively short, we assume there are only so many reinstallations. Again, beware that we deliberately chose this window without any research regarding the real reinstall rate, which may differ based on the category/use case of the specific application.
Below, you can see the number of unique values for each ID and the number of unique device models captured in this data.
AndroidID: 13 402 601
FingerprintV3: 22 525 265
MediaDRM: 13 285 081
InstanceId: 13 740 706
Distinct device models: 14 175 (i.e., Pixel 4, SM-G973N, ONEPLUS A5000, LG-H930, …)
At first glance, we noticed the number of FingerprintV3, which is much higher than the numbers of the other IDs. This could be caused by the behavior of the FingerprintV3, which changes whenever users change some of the 32 observed fingerprinting signals.
After that, we looked at the co-occurrence of the IDs to see the relation between them.
How to read the table below: One AndroidID has 1.00557 unique MediaDRMs, and 0.54% of unique AndroidIDs have more than one MediaDRMs.
Based on the data, we can’t say what a “different device” is (as we are still looking for the “best” identifier).
Let’s look at how many models per ID there are on average. Remember that it is desirable for us to have the least number of collisions (distinct devices with the same ID) — we expect the IDs to have only one associated model. A quick glance over the table below will tell us there truly are some discrepancies.
Based on the data analysis, we can state the following:
FingerprintV3 has too many values compared to other IDs, making it less useful in our scenario.
One AndroidID/MediaDRM/InstanceID usually has more FingerprintV3s.
AndroidId and MediaDRM are roughly 1:1; some MediaDRM instances have multiple AndroidIDs (more than AndroidId has MediaDRMs).
In some cases, one AndroidID has multiple InstanceIDs (more often than MediaDRMs), similar to the relationship between MediaDRM and InstanceID.
InstanceID is more bound to AndroidID than MediaDRM.
AndroidID has only one model (with a tiny amount of outliers).
MediaDRM usually has one model, but there are a few collisions (more than in the case of AndroidID).
InstanceId falls somewhere in between the models.
Overall, the best of these identifiers seems to be AndroidID, followed by MediaDRM. InstanceId can also be helpful, but less so than AndroidID. FingerprintV3 is useless in our scenario. Since AndroidID changes after the reinstallation and is relatively easy to spoof, MediaDRM seems to be the most suitable for fraud detection.
However, MediaDRM seems to have quite a few collisions (based on our analysis of the models). We have discovered that the collisions occur most often with devices of the same manufacturer (i.e., devices of the same manufacturer are much more likely to have the same MediaDRM than devices of different manufacturers). Here are some numbers for you to get an overview:
0.005% of MediaDRMs have more than one manufacturer
0.55% of MediaDRMs have more than one model of the same manufacturer
The mean number of manufacturers per MediaDRM: 1.000085
The mean number of models of one manufacturer per MediaDRM: 1.006362
After many attempts (that we won’t elaborate here), we have tried experimenting with a combination of MediaDRM+model as a potential ID.
Example of combined MediaDRM+model of some Google Pixel 4: e3af1aa4dacb6b6637846488b511e7643c6ac20b65c95baad164b122ecb036b6+Pixel 4
Below is the same table of co-occurrences as above, now containing relations with MediaDRM+model:
We can see that the MediaDRM+model behaves better than the original MediaDRM — each MediaDRM+model has lower number of other IDs associated with it, meaning that we have avoided a few collisions (even though we cannot quantify that amount exactly, but the minimum bound is estimated by the MediaDRM — MediaDRM+model numbers).
While making the ID as a combination of two characteristics, we might run into an issue with one device having more IDs. However, this should not be the case with the MediaDRM+model, as one device should have only one model associated with it (i.e., one physical unit of Google Pixel 4 phone should always have only and only model name “Pixel 4”).
Therefore based on the data, we suggest using a simple combination of MediaDRM and device model as an ID for the examined case of fraud detection.
We’re tackling a challenge in mobile device identification — how to block fraudster devices without compromising user privacy. Mobile app owners face issues with users evading payments and exploiting bonuses through multi-instancing — reinstalling the app multiple times. Unreliable device IDs make it tough to identify persistent bad actors. Our findings recommend prioritizing MediaDRM over device fingerprinting (or even better combination of MediaDRM and device model) for effective blocklisting. Don’t forget to enhance security with layers like AppiCrypt, RASP, and KYC solutions. Every scenario is unique, so for tailored guidance, contact Talsec security experts at info@talsec.app.
Written by Dáša Pawlasová, Matúš Šikyňa, and Tomáš Soukal
Boilerplate addressing vulnerabilities that standard setups often overlook.
In today’s digital landscape, mobile apps are not just about functionality—they’re also attractive targets for fraud and data theft. Security has become a fundamental part of app development, especially for apps handling sensitive user information. This article introduces a powerful option for app developers concerned with security: combining Ignite by Infinite Red, a leading React Native boilerplate, with freeRASP from Talsec—a free RASP solution—alongside other solutions to build secure and scalable apps.
React Native Secure Boilerplate: https://github.com/talsec/react-native-boilerplate
Ignite by Infinite Red is a robust React Native boilerplate featuring a CLI, component generators, and more. With over 12.2K GitHub stars, Ignite supports both Expo and bare React Native projects. It’s TypeScript-ready, utilizes MobX for state management, React Navigation for routing, Apisauce for REST APIs, and Jest for testing.
React Native's core features, such as Flipper, Reactotron, and Expo support, are enhanced by Ignite, which streamlines their use by providing pre-configured setups and simplifying integration. It also eases state management with MobX and ensures smooth state restoration by incorporating AsyncStorage with MST.
Ignite’s CLI can be accessed using npx for an always-updated version. You can create a new project with:
For vanilla React Native: npx ignite-cli new newApp
For Expo-powered projects: npx ignite-cli newApp –expo
Unlike other boilerplates that focus mainly on speed or provide a basic setup, this one is built for developers creating apps in high-risk industries like finance, healthcare, and e-commerce, where security is critical. The Ignite + freeRASP solution provides real-time protection against threats such as code tampering and unauthorized access, addressing vulnerabilities that standard setups often overlook. It’s designed to safeguard sensitive data and offer enhanced security for fraud-prone apps.
Disclaimer: Other solutions, such as paid options or even DIY approaches, may be suitable depending on your needs.
freeRASP is a lightweight Runtime Application Self-Protection (RASP) solution that provides real-time protection against a variety of threats. It’s built for easy integration and allows your app to react to detected risks automatically, like jailbreaking, tampering, or reverse engineering. Whether your app handles sensitive data or operates in an environment prone to fraud, freeRASP offers security features for post-launch protection and doesn't require external infrastructure, making it an accessible choice among several RASP options.
Real-time Threat Reaction: Through a comprehensive API, freeRASP can immediately respond to detected attacks and security threats, providing dynamic protection for your app.
Ease of Integration: The solution features a simple download and installation process, complemented by clear source code snippets, ensuring a smooth integration experience.
Minimal Performance Impact: freeRASP is designed to be lightweight, which means it provides robust security without compromising the app’s performance or user experience.
Weekly Security Reports: freeRASP sends out regular email reports that detail the security status of your devices and the integrity of your app, helping you stay informed about potential vulnerabilities.
Compliance with OWASP MASVS V8: It meets the OWASP MASVS V8 standards for resiliency against reverse engineering, ensuring your app is protected against common reverse engineering threats.
RASP is designed to detect and respond to threats in real-time. Here's a breakdown of how RASP solutions like freeRASP typically work:
Runtime Monitoring: Constantly checks for anomalies such as debugging attempts, code injections, or use of hooking frameworks like Frida or Xposed.
Periodic Scans: In addition to real time monitoring, freeRasp schedules periodic scans that run deeper into the app to check for irregularities and tampering.
Real-Time Responses: This enables Rasp to immediately take action against security breaches. Using predefined callbacks the app can be programmed to perform specific actions, such as alerting the user, restricting access to sensitive functionality, or even shutting down the app entirely.
Reporting and Alerts: freeRASP also compiles detailed weekly reports that summarize the security status of the app. These reports provide insights into any detected vulnerabilities, unauthorized access attempts, or security breaches. Developers can use this data to track trends in threats and take proactive steps to address vulnerabilities before they become serious problems.
Rooted or Jailbroken Devices: Protects against unauthorized access from tools like su, Magisk, unc0ver, check1rain, and Dopamine.
Reverse Engineering: Prevents attempts to analyze or manipulate your app’s code.
Hooking Frameworks: Detects and blocks frameworks like Frida, Xposed, and Shadow.
Tampering and Repackaging: Identifies and responds to unauthorized modifications or repackaging.
Untrusted Installations: Prevents installations from unofficial sources or app stores.
System VPN control: VPNs can obscure the user’s actual IP address and route data through servers potentially under external control, which might interfere with geographical restrictions and bypass network security settings.
Developer Mode control: Allows deeper system access and debugging capabilities that can bypass app security measures.
For more detailed information on these checks and their significance, visit the freeRASP docs.
Integrating freeRASP with Ignite is straightforward and ensures your app is fortified against real-world security threats. Ignite accelerates development, while freeRASP delivers critical security features that safeguard your app. Integrating freeRASP with Ignite involves a few straightforward steps. For detailed instructions, check out our GitHub repository and Medium article.
Install the freeRASP Package: Add the package to your project using yarn with yarn add freerasp-react-native. For iOS, run Pod install.
Configure freeRASP: Set up the necessary fields (e.g., package name, certificate hashes) in your configuration file.
Set Up Threat Reactions: Define how your app should respond to detected threats by creating an object mapping threat types to response functions.
Initialize freeRASP: Use the provided custom hook to start threat detection with your configurations and reactions.
If you are interested in knowing additional details you can refer to the freeRASP documentation.
With a brief outlook on how to configure freeRASP you might want to get a project up and running. Let’s look at how you might write code for a small “Hello World” project.
Begin with creating a react native project using Ignite. Use the following commands to start your app:
Install and configure freeRASP: First, create a configuration file named ‘freerasp.config.js’, where you will define your app's security and threat response settings. After that, use the useFreeRasp custom hook to initialize freeRASP. Here’s an example:
Combine all the elements:
There you have it, you've now successfully built your first Ignite + freeRASP project with just a few simple steps. More importantly, with just a few lines of code, you've fortified your app against major security threats. This is a significant achievement because it allows you to implement strong security measures without needing to dive into the complexities of cybersecurity. With freeRASP, you can integrate a strong protection layer into your app, providing a safer experience for users. For those looking for even more extensive coverage, paid RASP solutions are also available.
You might have secured your app with RASP but now it’s your turn to play a part. As a developer it is essential to follow best practices when building web or mobile applications to ensure your app is completely secure, here are a few tips:
Always use HTTPS for secure communication between your app and server. Implement SSL pinning to prevent man-in-the-middle attacks.
Ensure you always build for production so that Metro Bundler automatically minifies your JavaScript code, making it harder for attackers to reverse-engineer. Additionally, for Android, enable code obfuscation at the native level by setting the ‘minifyEnabled’ and ‘shrinkResources’ flags in your build.gradle file. This process further protects your code from being easily understood or modified.
Ensure that strong authentication mechanisms, such as OAuth or JWT (JSON Web Tokens), are used to verify user identities.
Never store sensitive data directly on the device. Use encrypted storage and secure system features like Keychain (iOS) and Keystore (Android).
Always vet third-party libraries for security risks. Make sure they are actively maintained and regularly updated.
In 2024, mobile app security is not optional—it’s essential. By combining Ignite for rapid development with freeRASP for runtime security, you can build a secure and scalable React Native mobile app with minimal effort. Developers can take advantage of freeRASP’s real-time threat detection and regular security reports to keep their apps safe without worrying about complex security implementations.
With a focus on fraud-prone industries and apps handling sensitive user data, this boilerplate provides everything you need to get started quickly while ensuring your app is protected against real-world threats.
Why wait? Explore freeRASP and other RASP options to secure your app today!
In an increasingly interconnected world, the need for robust application security has never been more critical. Capacitor, with its remarkable ability to build cross-platform apps using web technologi
In an increasingly interconnected world, the need for robust application security has never been more critical. Capacitor, with its remarkable ability to build cross-platform apps using web technologies, empowers developers to create stunning applications with ease. However, as the capabilities of our apps grow, so does the importance of safeguarding them against a myriad of potential threats.
With a native runtime such as Capacitor, it is fairly easy to turn any web app into native apps for both Android and iOS. You can quickly use the native APIs and access common device functionality, which is awesome, but at the same time, it adds another level of complexity because when you access native APIs, you are imposing yourself to native security issues as well. And trust me, you don’t want to underestimate these challenges.
As a practical example, consider one of the most common security concerns: reverse engineering. Mobile apps are typically distributed in formats like APK (for Android), AAB (Android App Bundles), or IPA (for iOS). These distribution files contain bundled JavaScript code essential for the application’s functionality.
Despite attempts to obfuscate the code through minification and adhering to industry standards like OWASP MASVS (Mobile Application Security Verification Standard), a person with the necessary knowledge can still extract your code with relative ease. There are even utilities like JSTool that can effectively reverse the minification and reveal the original code, potentially exposing sensitive keys and API calls. Afterwards, it’s all in the hands of the attacker.
Successful attacks like these may lead to loss of revenue, exposure of sensitive data, damage to the brand and reputation or leaked intellectual property. And that’s where we want to help you.
Talsec freeRASP is a freemium mobile security SDK designed to make app protection straightforward and accessible. It offers robust protection against a range of threats and is supported on both Android and iOS platforms. freeRASP also provides customized modules for a number of multi-platform tools, now including Capacitor.
From a developer’s perspective, freeRASP acts as an additional protective layer, simplifying the handling of certain attack vectors. This allows you to focus on other critical aspects of your app while safeguarding your users. freeRASP can detect and inform you about various attack scenarios, including reverse engineering, repackaging, cloning attempts, and much more.
Join us as we explore how freeRASP integrates with Capacitor, helping you defend your apps against attacks and vulnerabilities, and ultimately, ensuring your users’ safety. Say hello to enhanced security and peace of mind for your Capacitor apps — let’s dive in.
Mobile app security is a complex challenge that goes beyond traditional security measures like encryption and certificate pinning. Attackers constantly seek vulnerabilities in your app that may not be immediately obvious. A single security breach can have severe consequences for your reputation and user trust.
The need for Runtime Application Self-Protection (RASP) solutions has grown significantly with the rise of mobile technologies. While there are several security libraries available, freeRASP stands out by offering comprehensive protection across various attack vectors.
Based on our experience, a selection of the most common attacks include:
App repackaging and cloning
Re-publishing of tampered apps
Running the App in compromised OS environments (rooted/jailbroken OS, hooking app during runtime, emulators)
freeRASP is designed to detect and mitigate these types of attacks, providing an extra layer of defense against evolving threats.
Now, let’s dive into the process of integrating freeRASP with the Capacitor platform. You can always find up-to-date integration manual along with detailed description of configuration in our GitHub Integration Guide.
To get started, install the capacitor-freerasp
plugin:
For Android, ensure that your project’s minimum SDK level is set to 23. Update your variables.gradle
file accordingly:
Import freeRASP in your app’s entry point file:
Configure freeRASP by providing the necessary settings. You’ll need to specify configuration for both Android and iOS, as well as common configuration options. Here’s a sample configuration:
To enhance security, consider obfuscating your app’s code. Obfuscation makes it harder for attackers to reverse engineer your app and disrupt freeRASP’s operations. You can enable code minification and obfuscation for Android in your build.gradle
file:
With this weekly summary, you get insights into your app’s security state, including detected threats and device characteristics. By keeping an eye on these reports, you can proactively address security issues before they become too severe and make your app even safer for users. If you are curious how such report looks like, take a look at the screenshot below 👇.
While freeRASP offers a robust free version, Talsec also provides commercial versions like RASP+ with advanced features and support. These versions offer additional protection, including API protection, App Integrity Cryptogram (AppiCrypt®), security hardening, and more.
RASP+ allows easy-to-implement API protection and App Integrity verification on the backend to prevent API abuse from:
Bruteforce attacks
Botnets
API abuse by App impersonation
Session-hijacking
DDoS
It is a unified solution that works across all mobile platforms without dependency on external web services (i.e., without extra latency, an additional point of failure, and maintenance costs).
Learn more about commercial features at talsec.app.
If you read through the whole article, thank you. Maybe now it’s time to check out freeRASP. It’s free, so there’s nothing to lose and who knows, maybe it will save you from a couple of sleepless nights.
We’d be happy to read your thoughts in the comments below 👇 or in one of our GitHub repos 📄.
Written by Tomas Psota, developer @ Talsec
In today’s mobile app ecosystem, ensuring your app is secure from piracy, tampering, and sideloading is more important than ever. With unofficial app stores and third-party platforms on the rise, developers face the risk of their apps being stolen, modified, or misused, often leading to revenue loss, security breaches, and reputation damage. One simple but effective measure to safeguard your app is enforcing install source restrictions, ensuring it only runs if downloaded from official stores like Google Play or the Apple App Store. This article explores how you can implement these checks and why it’s crucial for app security.
Distributing an app through unofficial channels opens the door to numerous security threats, many of which could have devastating consequences for both the developer and users. Unauthorized installs can lead to significant breaches in security for several reasons:
Tampered versions of the app
Lack of official updates and security patches
Data leaks and privacy concerns
Exploits for ads or in-app purchases
Gateway for broader attacks
Commonly, fake applications are installed through the internet browser, file manager, cloud storage, or various messaging apps.
One common scenario is that the app being installed has been tampered in order to skip verifications of some kind or in order to add malicious code to it. As an example, an attacker can use apktool
to decompile the apk:
This gives back a smali version of the app that can be changed later on. Think of smali
code like an assembly-like language that is a low-level representation of the compiled Java code. That can be modified by maybe adding a key logger function of some sort.
Than is as simple as repacking the app with apktool
and then resign the apk
This high-level example shows how dangerous it can be to install an app like this for both developer and user. Users who unknowingly download these tampered versions may be exposed to malware, spyware, or data-stealing mechanisms that compromise their personal information. This type of unauthorized access could include reading sensitive files, intercepting user data, or even hijacking user accounts. Developers can be harmed both in terms of their reputation and earnings. Modified app versions may disable ads, unlock premium features for free, or provide unauthorized access to paid content.
One basic strategy is to check the install source every time the user launches the app and react accordingly.
Let’s see a quick and easy example using Flutter. Keep in mind that we will write some native code for Android and iOS, so you can use the same code if your app is native only or if you want to use it in any other framework.
So first of all, let’s create a new Flutter project with flutter create check_install_source
. You can remove the main.dart
file entirely and replace it with the following, starting with the necessary imports and the classi main declaration:
Then we can create a MyApp
class
In the actual MyAppState
we can implement a simple build
method and the initState
:
Now let’s add a new method called _checkInstallSource in the initState
So that we can implement it as following:
What’s happening here is that we are calling specific native function using flutter’s method channels (https://docs.flutter.dev/platform-integration/platform-channels) so that we can perform some action in the native side. Of course we are catching exceptions that may occur.
When we call getInstallerPackageName
**Android method we will ask what the install source is. In this case we are checking against com.android.vending that’s the Google Play Store but you can also check plenty of other alternative stores like Samsung Galaxy Store com.sec.android.app.samsungapps.
On the other hand, when calling validateAppStoreReceipt
iOS method we are checking that an App Store receipt is present. Even on free apps, Apple attach a receipt file to verify the authenticity of the executable. Of course just checking if the receipt is there or not could not be enough so you can perform additional verification or send receipt to your server for validation (https://developer.apple.com/documentation/appstorereceipts/validating_receipts_on_the_device).
Now, before checking kotlin and swift code, let’s see what we can do with those informations and let’s implement the _showErrorAndExit()
method.
Keep in mind that’s just an example to alert the user. Exiting an app with exit(0)
it’s not usually recommended because Apple may reject your app when submitting it to the AppStore.
Now open the MainActivity.kt file in Android folder and swap the content with necessary import first:
and than change the MainActivity class as following:
In this chunk of code we are implementing Flutter method channel in Android counterpart, getting ready to listen for the same method getInstallerPackageName
that we implemented in Dart. Using packageManager
we can get the installer package name and pass it back to Dart.
We can move to iOS folder opening AppDelegate.swift and adding imports:
We can proceed editing didFinishLaunchingWithOptions method to let Swift know what method need to be respond to:
Last step is to implement the isValidAppStoreReceipt() method in the AppDelegate class:
Your app should now be able to check the install source and force exit if it’s an unofficial source (in this example).
Even if you have verified the install source of an app this is just the initial stage of ensuring that only genuine and authorized versions are installed, developers still need to undertake other steps to ensure that their apps are safe. Here are some effective strategies and tools that developers can leverage to enhance security.
Flutter / Dart are typically more resilient against reverse engineering as the code is minified during the compilation (not really obfuscated). It's common to offload sensitive parts of code to domains that can be obfuscated more easily: Java/Kotlin, Swift, and especially C/C++ languages can be obfuscated by ready-made obfuscators.
Code obfuscation remains one of the easiest ways by which one can protect his or her application. Consumer objectives can be achieved using tools such as ProGuard for Android or LLVM Obfuscator for iOS because such tools distort code within the app, making it impossible for an attacker to understand what the app does. While renaming classes, methods, and variables, the work of an attacker significantly becomes more complex, depriving him even an attempt to begin to decompile and adjust the internal functioning of the application.
Another interesting project worth checking out ishttps://obfuscator.re, that’s based on
dProtect an Android bytecode obfuscator based on Proguard O-MVLL is an obfuscator based on LLVM that uses the new LLVM pass manager,
-fpass-plugin
to perform native code obfuscation
One must recognize when an app is running in an environment such as a jailbroken iPhone or iPad or a rooted Android device. These devices usually eliminate crucial security components, thus rendering them prone to hacking. There is always the possibility of root and jailbreak detection, so existing applications cannot run within these breeches.
freeRASP (Runtime Application Self-Protection) (https://docs.talsec.app/freerasp) refers to an all-inclusive security solution whereby your mobile application can be monitored in real-time. It goes beyond basic checks like jailbreak or root detection by offering a full suite of security features, including:
Integrity Check: Identifies the state or level of modification of the app in order to determine if it has been modified in anyway. Debugging Detection: Recognizes whether in a specific app it is currently being debugged, or, for instance, during reverse engineering. Repackaging Protection: They also shield users against other attackers altering and repackaging their applications. Anti-Hooking: Intercepts and protects against such tool as Frida from injecting their code into the app during its execution. With the help of freeRASP, developers can prevent complex threats, including tampering, reverse engineering, and runtime manipulation. The application is free of charge and comes with powerful addressing security options compared to other powerful addressing security options that can easily be incorporated into existing mobile applications.
It is, therefore, important to consider multiple levels of security when developing applications for the current mobile environment. Verifying install sources is a good start, but by using tools such as freeRASP, runtime protections, and server-side checks, developers can offer a much safer environment for the applications. This shields the users from such applications and possible data leakage and your brand and business from the possible repercussions of a malicious app.
Recently, Talsec team has dedicated time and effort to explore different options for secure storage on the Flutter platform. While storing data is a straightforward task, ensuring its security requires careful consideration.
This article assumes you are familiar with:
How data storage works on native platforms
, and how they are used
RASP (Runtime Application Self Protection) Security technique that actively defends application by real-time controlling the security state of the device, integrity of the OS and App.
A quick recap of what is available as of today. If you are familiar with these packages, feel free to skip to the next section.
Another important consideration is that although hardware-backed keystores may offer greater resilience against key extraction, they still face the same vulnerability as software-backed keystores — they are not immune to runtime attacks. The data (which are encrypted using keys stored in the keystore) can still be accessed using rooted devices, repackaged/tampered apps or by using hooking frameworks at runtime.
So we came to conclusion that protecting data at rest on the device using SW-based security in combination with RASP can be good enough for many cases and even have considerable advantages.
By incorporating a software-backed keystore into RASP (Runtime Application Self-Protection) solution, we can simultaneously address two critical aspects:
Reliability Enhanced RASP solution will offer a dependable keystore mechanism that does not rely on secure hardware. This means that even on devices lacking hardware-backed security features, this solution will ensure the integrity and protection of cryptographic keys.
Security As mentioned earlier, the keystore itself is still vulnerable to threats such as root access and runtime hooks. However, a keystore that closely integrates with RASP would have this problem mitigated, as it could determine whether or not to store/retrieve data based on the current security state of the device.
With the integration of a software-backed keystore, enhanced RASP solution provides a comprehensive and reliable approach to data protection, overcoming the limitations posed by both hardware availability and copromised devices.
This solution is also not perfect as might look. We also have to consider problematic parts:
RASP is not unbeatable While RASP adds an extra layer of security, it’s not an universal solution which will solve problem once for all. It just adds complexity for attacker to deal with. Once RASP is defeated, this solution becomes “plain” SW-backed keystore. It’s also important to note that RASP can’t replace traditional security measures.
HW is more secure As mentioned earlier, HW-backed keystore performs way better when it comes resiliency against data extraction. Also finding and misusing issue in HW is way harder than finding issue in software implementation of SW-backed keystore.
If you choose SW-backed keystore it’s important consider if you take traditional implementation relying on crypthography or you’ll take storage with additional security layer.
What do you think? Would you rely on SW-based secure storage SDK for Flutter with hardcoded obscured encryption key?
Share your thoughts and experiences in the comments below! 👇📝
Did you know that you can remove plugins dynamically from a Flutter app on Android?
During the implementation of a new feature on freeRASP (more about it ), we noticed that unregistering of plugins is possible using the class. While it may seem unimportant, we decided to push the limits and explore potential attack vectors tthat could lead to the complete disabling of plugins from an external source. As a result, we conducted a small check of the plugin architecture security on Flutter. During this investigation, we discovered what we consider to be a serious problem.
If you have a class reference available, you can also selectively remove specific plugins:
You can follow these measures if you want to make sure, that your code is protected againsts such attacks:
🔒 Opt for reputable plugins — Choose well-maintained plugins with a considerable number of likes and positive user feedback.
🔒 Inspect the plugin’s source code — Take a closer look at the codebase for any suspicious lines or potential vulnerabilities.
🔒 Always obfuscate your application — Apply obfuscation techniques to make your app less readable and more obscure.
RASP (Runtime Application Self Protection) Security technique that actively defends application by real-time controlling the security state of the device, integrity of the OS and App.
For context, AppiCrypt is an app attestation tool that protects your API by generating a cryptogram — information about the security state of the device, which is then used in the request header. The backend then checks the cryptogram to determine whether the device is compromised and decides whether to allow or deny the request.
Since the plugin cannot generate a cryptogram (CryptogramFailureException
is thrown due to the PlatformException
thrown by MethodChannel), the app can be considered untrustworthy. Without a cryptogram, you cannot make network requests backed by AppiCrypt.
Therefore, as a security measure, we can also add:
🔒 Dynamically validate plugin functionality — If the plugin throws a PlatformException
, it can indicate that it is unable to communicate with the native side.
While it won’t directly tell you that the plugin has been disconnected, it can give a hint that something unusual is going on.
Stay safe and code with confidence! 💪
Written by Jaroslav Novotný — Flutter developer
It is predicted that there will be whopping . With great power comes great responsibility, and every experienced software developer should thrive to follow security standards to ensure that their app is secured against cyber criminals. Technologies like RASP (Runtime Application Self-Protection) are made to shield your app against attacks that occur in the runtime. In this article, we’ll show you a RASP-based security library for your React Native app which can detect a wide range of potential attacks and vulnerabilities.
Well, statistically yes. But reality is quite different. When your app is republished or the data of your users are compromised, it’s too late to think about security. Your reputation is now weakened. You are that ‘one in a million’ person that was unfortunate enough. However, if you found this article, then you most likely want to find out how to make your app more secure. And this is a great starting point!
freeRASP is a mobile in-app protection and security monitoring plugin. It aims to cover the main aspects of RASP (Runtime App Self Protection) and application shielding, enabling the app to defend itself against threats. It allows mobile applications to check the security state of the environment they run within, actively counteract attack attempts, and control the integrity of the app.
From the developer’s point of view, freeRASP serves as an extra protection layer that helps you to handle certain attack vectors with ease, while you can aim your focus on other areas. You are also protecting the users of your app as freeRASP is able to detect and take actions if the app is being executed on a rooted or jailbroken device, whether the app is tampered, etc.
freeRASP is designed to combat many significant attack vectors, thus creating an obstacle that prevents your app from intrusion. This gives you a real advantage against other apps which do not protect themselves in any way.
You can add freeRASP the same way as you would with any other package. The plugin is installed via your favorite package manager. With yarn, for example, you can do it like this:
This is a place where you set up required fields (package name, signing certificate hashes, bundleId, teamId), which will help freeRASP to detect threats correctly. Don’t forget to add also your email address so you don’t miss your regular security report (more on that later). The configuration might look like this:
After a threat is detected, freeRASP fires an event that is consumed by your app. With freeRASP, it’s the developer’s responsibility to configure what should happen after such event is registered. You can for example kill the application, notify the user that a threat has been detected or just ignore the threat. It’s all in your hands. Just create an object that has threat name as a key and function as a value, like it is shown in the example below:
Good, all setup is done! The last missing part is to start looking for threats. We provide a custom hook that handles all required logic for you, as is registering and unregistering of the listeners. The hook is a part of the freeRASP package and needs to be imported:
Now pass your config and threat reactions to the imported hook:
The hook will now initialize freeRASP with your configuration and start to look for threats. That’s it!
There are the dev and release versions of the library. The dev version should be used only during the development process of the application as it disables some of the checks (e.g. if you would implement killing of the application on the debugger callback). In other cases, you always want to use the release version. On Android, it is handled automatically, whereas, on iOS, the step is a matter of adding a pre-built script into the run phases and embedding a symlink to the correct framework. Do not worry, it is quite easy ;)
freeRASP is available to everyone, free of charge. However, it uses a bridge between JavaScript and native code, which is essentially an additional place that could be exploited. We are able to remove this redundant communication while still keeping your app safe. You can read more in the Enterprise Services section down below.
This example presents a report of a mid-sized FinTech app:
The demand for secured apps nowadays is already high and will only increase in the future. Therefore developers should thrive for secure solutions. freeRASP is a tool that can help you to achieve this task. With all its security checks, it can be your good friend and keep you out of trouble. freeRASP is a powerful tool that gives you freedom of choice in how you set up the reactions to detected incidents. What’s more, it is available as a package, which makes the integration pretty straightforward. Don’t forget, freeRASP is available free of charge, why don’t you try it then?
written by Tomas Psota, developer at Talsec
Either you want to hack Flutter apps, or you want to make them bulletproof. I will show you how it’s done. My name is Tomáš Soukal, and I am a security consultant at Talsec. This guide is unique in its focus on Flutter apps, so you don’t have to read through iOS or Android-only specific hacks over and over again.
Part 1 (this article) ↓
Disassemble app.
Extract its secrets.
Make a fake clone.
Check every transmitted JSON.
Inject code.
Steal authentication tokens.
and attack the API.
After reading this short guide, you will know how to hack and how to protect against mobile threats.
Disclaimer: Don’t do this to anyone with ill intent, as this is legit hacking. Use this only for learning purposes.
“They stole our apps by reverse engineering and republished.” Hacking and protection go hand in hand. I have seen dozens of questions on StackOverflow about mobile application security. Some people ask for remediation only after their app is hacked, and others take security in mind from the start. I collected a few of those posts:
Let’s examine what do hackers use.
These are key tools you should know about. Hacking is a time-restricted activity. With proper tooling you will be able to dive deep into app’s internals in a no time. Time is money.
MobSF is an automated, all-in-one mobile application (Android/iOS) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis. Run these three commands to install it, drag’n’drop any Flutter APK and watch the magic happen:
Note: don’t run random code found on the Internet. Check the original source and verify it’s safe to run.
MobSF can do compliance checks, search for secrets, embedded URLs and find common issues automatically. It can also help you to uncover vulnerable modules (3rd party libs) and unsecured entrypoints (receivers, deep links).
Let’s proceed with some exciting stuff. I always imagine app’s stored data as a chest full of precious gold. Once the app lands on your rooted device (or enable Developer Settings), you can freely inspects it’s embedded data and assets. You will find databases, access tokens, API keys, bearer tokens, media assets, Shared Preferences. Shared Preferences files are particularly interesting as they are often misused to store sensitive data like login credentials.
Let’s open Total Commander.
In the Total Commander, I can see the XML file with this preference:
Here it is:
I can even modify this value and the app will immediately update (thanks, Flutter) the value in the UI! I hope you are at least a little worried about sensitive data in your shared preferences now. Before I will show you more (in the next part), let’s discuss the rooting issue.
FYI, Talsec provides technologies like Secure Storage or Obfuscation to make attacker’s life harder ;)!
Some developers refuse to believe there are vulnerable mobile systems (in 2022). They are convinced that the Android/iOS sandboxing model and security practices are decent nowadays. They may be wrong.
Privileged access rights escalation breaching system security model is still possible in many scenarios. Check these vulnerable systems:
Device or emulator can be rooted on purpose
App may be jeopardized by a 3rd party dependency
New OS exploits may be discovered / OS may be unpatched
HW exploits
Have you heard about Dirty Cow, Log4j, and Janus vulnerabilities?
Subscribe Talsec and maybe try to crack-open some Flutter app in the meantime!
written by Tomáš Soukal, Security Consultant at Talsec
OWASP Mobile Application Security guides all phases of mobile app development and testing. The Verification Standard and the Testing Guide will provide you with a security standard and a baseline for mobile app security verification curated by a community dedicated to improving software security. Put in the right RASP suite to get the best passive and active security mix.
Part 1 () ↓
Disassemble app.
Extract its secrets.
Part 2 (this article) ↓
Make a fake clone.
Check every transmitted JSON.
Inject code.
Part 3 () ↓
Steal authentication tokens.
and attack the API.
While you could fiddle with Flutter’s binary libapp.so
file, I would just inject code into MainActivity.smali
file, which is present in every Flutter Android app. The code used in this file is called smali. You can modify it as you wish. This can be misused to add a custom Activity, paywall, ads, or for credential harvesting. An adversary may be able to load native library containing reusable malware code. In my experience, the injection of hidden malicious native code is actually quite common.
This is the MainActivy.smali file in a stock Flutter app after being disassembled with apktool:
Example 1: Hello World
This code is a simple ‘Hello, world!’ string written into log.
Example 2: Open browser intent to a malicious website
This code will prompt a user to open the adversary-controlled phishing page.
Let’s change the side and assume you want to protect your app against such attacks instead. I have great news! There is a standard for that. It’s called OWASP Mobile Application Security (OWASP MAS) which can guide you. It is a comprehensive guide for mobile app security with actionable solutions for many problems.
I should now advise you to visit the OWASP MAS using the link below. But it would also mean I would lose your attention. If you promise that you will return here, you can click it:
MAS Verification Standard (MASVS) will help you to understand something called security levels (L1 Standard Security, L2 Defense-in-Depth, R Resiliency). It will also introduce you to respective categories and their requirements:
MAS Testing Guide (MASTG) holds platform-specific detailed content about all security techniques. Unfortunately, it is targeted at iOS and Android devs and is less beneficial to Flutter devs.
MAS Checklist is a sheet used to check all requirements one by one to ensure nothing was left.
JSON attacks, also known as JSON injection, refer to a type of backend web application vulnerability that occurs when user-supplied data is passed through a JSON parser without proper validation or sanitization. This can allow an attacker to inject malicious code into the JSON data, which can then be executed by the application.
To make a JSON attack, an attacker would need to craft a malicious payload that is designed to exploit the vulnerability in the target application. This payload could be included in an HTTP request, hidden in a file, or delivered through some other means. Once the payload is delivered to the application, it would be parsed by the JSON parser and executed, potentially allowing the attacker to gain unauthorized access or perform other malicious actions.
I have chosen an arbitrary automotive app featured on the Flutter homepage. Just imagine that hackers would have discovered a vulnerability in such an app, allowing them to open the car’s trunk remotely. Such scenarios are actively researched nowadays and serve as a reminder of the importance of regularly updating software and maintaining strong security measures to protect against hackers.
Seeing the capabilities of this app makes me wonder what would happen if someone could exploit it. Remote unlock, car horn, remote cameras, car location and other super-sensitive operations can be invoked within this app.
I downloaded the app from my testing device to my computer and reFluttered it:
At this moment, I am able to inspect every request, uncover hidden advertising campaigns, and so on. In general, this opens access to data like:
API architecture
Source URLs
HTTP headers
Bearer tokens
Transmitted data (i.e., JSON)
Key features are the detection and prevention of root/jailbreak (e.g., unc0ver, check1rain), hooking framework (e.g., Frida, Shadow), untrusted installation method, and App/Device (un)binding.
Speaking of OWASP MAS levels, you would mostly be interested in RASP if your app should be compliant with R-level oriented on resiliency aspects. Actually, many devs integrate freeRASP as a future-proof solution to stay ahead even before their app truly needs R-level. This is something I am really proud of.
Thank you for reading the second part of this guide. It’s always great to have an interested and engaged reader, and I appreciate your time and attention. I hope the information I’ve provided has been useful and informative! Thank you again for joining me on this journey.
Part 3 of this series will be available soon. Subscribe to Talsec and maybe try to crack-open some Flutter app in the meantime!
written by Tomáš Soukal, Security Consultant at Talsec
Gone are the days of locally-held data and standalone applications. With the rise of smartphones and portable devices, we are constantly on the go and reliant on network calls for everything from social communication to live updates. As a result, protecting backend servers and API calls has become more crucial than ever.
Most of the time, the application uses an API to make HTTP requests to the server. The server then responds with the given data. Most devs know and use it all the time. However, we often have data with restricted access — data only some users/entities can obtain. Moreover, they need to provide a way to prove who they are.
A typical method for authorizing requests (and therefore protecting data) is to use tokens signed by the server. The authentication request is sent to the server. If authentication is successful, the server issues a signed token and sends it back to the client. The application will use it on every request, so the server knows it is talking to an authorized entity. Although the token is used during its validity period (usually minutes), it is long enough to exploit the leaked token even manually.
The current standard is to carry these requests over HTTPS, which TLS protects. The whole process is encrypted, so it will not be useful to attackers even if they manage to catch a request. This ensures the confidentiality of communication — the attacker knows there is some communication but does not know its actual content.
Attackers can impersonate a legit application if they steal a token.
There are multiple ways that the app can be attacked and compromised in order to steal the token and use it for malicious purposes. Here are a few clear examples:
If an attacker gains access to a rooted device, they can misuse the token.
An attacker can create a tampered version of the app, distribute it, convince the user to install it, and then obtain a valid token from the tampered app to misuse it in an automated way.
For the purposes of this demonstration, we will be focusing on the second option.
The solution to these issues is to check clients’ integrity to ensure that:
A communicating party is a legit client — this blocks requests from other sources, such as Postman.
A communicating party can be trusted — the client’s integrity is intact (e.g. not tampered with), and it is running in a safe space (e.g. unrooted device).
Disclaimer: While we provide information on legitimate hacking techniques, we do not condone using this information for malicious purposes. Please only use this information for educational purposes.
The demonstration is presented on an Android platform; however, it is important to note that the iOS version is very similar in nature, and the same principles and considerations discussed stand the same.
Let’s have an imaginary company that provides meal tickets as cash credit in their app. The app uses Firebase Authentication to authenticate users. An operation to send credits from one person to another is handled by the Firebase cloud function. To identify which user is sending their credits, JWT ID Token is used. This token can be retrieved from the Firebase instance after the user is successfully authenticated.
Now for the hacking part — an overview of the attack.
First of all, we need to gain access to the application scope itself. There are several ways how this can be done. In most cases, rooting a device would give us the access we need. However, for our demonstration, we choose application repackaging.
Wait a minute. Where would an ordinary user get a tampered app?
Getting the format of API requests can be done by self-proxying. After that, you recycle this with a stolen token using Postman, curl, or other software.
To strike a balance between “too abstract” and “too complicated”, some implementation details will be omitted as a story for another time.
Initially, we acquire the valuable APK file of an application. This can be achieved in many ways. The technique described here uses adb — a standard tool which should be in the toolbelt of every developer.
After installation of the app, we need to get its package name. Using the terminal, we can list package names of all installed apps/services using the command:
This gives us a way shorter and cleaner list. Moreover, we found our wanted package name: com.mycompany.letseat
Now we need to get the path where the APK file is stored. This time, we use the shell functionality of adb.
This returns the path where APK is located. Using adb pull, we can extract this APK to our desired destination.
Now we finally have the APK, which we will tamper. In the next section, we will decompile it, modify it and repackage it.
To decompile the APK, we will use the apktool d command. We are also going to set the output directory for better clarity.
The APK is extracted into the decompiled_apk folder and has a structure like this:
We recommend you to play around a bit and think of new ways to mess around with the application (e.g. you can see flutter assets there — you could inject ads using assets). What we care about for now is a folder named smali and its subfolders com/mycompany/letseat (what does that path remind you of?).
The smali folder contains decompiled code of the android part of the Flutter app. Let’s see MainActivity.smali for reference.
It looks like some broken version of C#. What is this smali thing anyway?
Smali code is an assembly language used in Dalvik VM — a custom Java VM for Android. What we did now is called baksmaling — getting smali code from Dalvik file (.dex). Apktool makes this “decompiling” for us, so we do not have to deal with .dex files. Smali code is primarily used in reverse engineering.
In the example above, you could make an educated guess — the init function is invoked, and this function belongs to the io/flutter/embedding/android package, and the function itself is in a file named V. Let’s try to verify this guess.
Path io/flutter/embedding/android exists, and there is a file named i.smali. It even contains multiple reference to the class’s constructor <init>().
However, something here is even more interesting. Look at some non-gibberish names: onCreate, onStart, onResume, onStop, onDestroy, … It looks like an Android activity lifecycle. We recommend you to check it out.
For now, all you need to know is that a lifecycle is a group of callbacks called when the app changes states (the app was launched, the app was put into the background, the device was rotated, …). We will choose onCreate as the place where we inject our code. However, this code has to be written in smali code. We have two options here:
Writing code directly in smali code (good luck with that)
Writing Kotlin/Java code, disassembling compiled code and copying that into the onCreate method
We are going to choose the second option. We are going to skip the creation and compilation of the APK. The most important part is the code itself:
In the onCreate method, we only call the steal() function. The stealing function then finds shared preferences, iterates through all files and logs their content (to keep this article concise, calls for the server are replaced by logging). Notice, that the first run (runs before first login/auth) will log “File not found”.
Now, we can build our application into APK and then decompile it. After decompilation, we will go to MainActivity.smali file and search for our steal() function. The smali code of steal() function looks like this:
What we need to do now is to merge two smali codes carefully.
Copy steal invocation from MainActivity.smali to i.smali
Insert steal function from MainActivity.smali to i.smali
Fix package references in i.smali
After examination, we can see that the steal() function invocation in the MainActivity.smali is translated as a one-liner.
However, it is invoked from the wrong package name. Since all related functions in the Let’s Eat app are in the i.smali file, we need to reference it. Let’s fix that.
Another surgical operation is copying the steal() function. After copying it, we need to update the package reference as well.
Notice this line. When we get the application information, we apply it to the current instance. Package reference is, therefore, MyApplication.
This would cause an error since you are referencing in non-existent package (in the “context” of the Let’s E`at app). However, you can use a reference to any android Activity. Therefore, you can rewrite this into the code below without any problems.
We successfully modified the code. Putting the project back into the APK is a straightforward process — using apktool, we do just that, and the apksigner will sign our package. Since there is no RASP protection to protect the app, the device will install it without any problem.
To rebuild the APK, we need to go one level above the decompiled APK (so we can refer to it by folder name). Then we use apktool.
A disadvantage of decompiling is that the signature used for signing is now gone. Because of that, we need to sign it by hand. An unsigned package is bad (and useless) because:
You cannot put it on the app store
You cannot install it properly (e.g. drag and drop the APK onto the emulator)
To sign an APK, you need a key. Since key generation is out of the scope of this article, we recommend you to go through the official Android developers guide.
For signing, you can use apksigner.
Now you have an APK containing malicious code which exposes JWT.
When we run the application, we can see the format of the stolen payload.
First, we will try to query the Firebase API itself. It is handy when an app has a public Firebase REST API.
We will need to grab Firebase project_id from the mobile app:
Second, notice key-value refresh_token and access_token from the Firebase file.
These can be easily misused with project_id. Since the endpoint is the same, we only need to provide valid values. Be aware that these tokens have limited validity, and you will need to get fresh ones quite often.
This request returns more data.
If you wonder where this project_id comes from, it is a google-services.json file which you can find in the Firebase console.
Forging requests in our example is done by providing access_token to the header.
We successfully transferred stolen money.
AppiCrypt makes protecting your backend API easy by employing the mobile app and device integrity state control, allowing only genuine API calls to communicate with remote services.
It generates a unique app cryptogram evaluated by a script on the backend side to detect and prevent threats like session hijacking (which we have just demonstrated), bot attacks or app impersonation.
The idea behind this technology is not just to protect APIs but to let your backend know that RASP controls were overcome or turned off by attackers. So gateway can easily block the session if the App integrity is compromised, and backends only process API calls if RASP controls check out.
Cryptogram is inserted into the header. There is no need to change the payload of the message itself.
Cryptogram itself is then an encrypted one-time value. You cannot modify it, and even if you manage to steal a payload containing a cryptogram, it is useless — a cryptogram cannot be simply reused. Nonce allows you to determine that the cryptogram belongs to your API call and isn’t replayed by an attacker. Using an old cryptogram will result in failure of its check (server will respond with code 403):
Where AppiCrypt excels is its integration. It does not require any integration with external APIs. It ensures low latency and does not introduce a single point of failure. The cryptogram is verified by locally running a simple script on your backend. AppiCrypt is a generic solution for all types of iOS and Android devices without dependency on Google Play or other OEM services.
In this article, we looked at one way of attacking a mobile application. We showed how Firebase tokens can be stolen from the app and used to attack the API. We also explained how an APK file could be decompiled, what smali code is and how to add malicious code. Finally, we learned how we could protect ourselves from this attack.
This article was focused on the Android platform, but a similar problem may occur on iOS or other mobile systems. From the user’s perspective, it is important to be careful when downloading and using applications from unverified sources and check their permissions and reviews. From the developer’s point of view, mobile security is a constantly evolving area that requires attention and updating of knowledge.
We hope this article helped you understand the risks associated with mobile security and taught you some ways to minimize them.
Written by Jaroslav Novotný — Flutter developer, Tomáš Soukal — Security Consultant and Tomáš Biloš — Backend developer
Use third-party solutions, which specialise in threat detection and real-time security monitoring (e.g. ).
Talsec team has recently been exploring ways to enhance data security on the Flutter platform. After conducting research, we are considering adding a secure storage feature to and solutions. As part of this process, we are analyzing the current state of secure storage options in Flutter and gathering insights from the community regarding their expectations for such a feature.
1️⃣ (Flutter Package) One common choice among Flutter developers for storage is the flutter_secure_storage plugin. This plugin offers key-value storage that leverages the native API of the target platform (SharedPrefferences, Keystore, Keychain,…) and provides a unified API for accessing them. While the data is encrypted, the current implementation of this solution is possibly vulnerable to a padding oracle attack (as mentioned in GitHub issues , ). This vulnerability means an attacker could decipher a message because of incorrect message alignment. However, this attack vector is theoretical and rarely applicable (there are attacks requiring less effort).
2️⃣ (Dart Package) Another popular option in the Flutter community is Hive, which provides a straightforward and user-friendly API for developers. Hive is known for its lightweight nature and fast performance, making it a reliable choice for storage in Flutter applications. Additionally, Hive offers built-in support for data encryption, specifically AES-256 encryption. When using encryption with Hive, it is important to note that you must provide an encryption key. Therefore, exercising caution regarding where you store the key and how you securely handle it is crucial.
3️⃣ (Flutter Package) sqflite is a Flutter package that simplifies the creation and management of local application databases by utilizing the SQLite database engine. With sqflite, developers can easily handle tasks such as storing user preferences, caching data, and managing structured information in their Flutter applications. Additionally, sqflite provides integration with SQLCipher, which guarantees the security of sensitive information. An encrypted database is initialized with a password. It is crucial to handle this password securely and not hardcode it — hardcoded keys are visible in reverse-engineered app.
We realised that while hardware-backed keystores are available on most devices, there are still many devices that lack this feature. Additionally, some devices encounter issues with hardware-backed keystores due to manufacturer-provided software. These keystore implementations either fail to perform their intended function or resort to software-backed solutions anyway.
In Flutter, the class plays a crucial role in managing plugins. The generated GeneratedPluginRegistrant
class utilizes it to register plugins, which are then executed during startup. However, you have the flexibility to create your own plugins, acquire plugin instances, and even unregister plugins if needed. Therefore you can create plugin which removes other plugins:
This can even be also achieved directly from your app’s MainActivity
on Android (which extends FlutterActivity
) without the need for malicious plugin. By leveraging a bit of reverse engineering and code injection (similar to what we discussed in our ), you can achieve this:
We faced the same issue at Talsec (link), while trying to hack our own products + and which are critical security components and should have maximum resilience. Finding at least a partial solution was very important to us. In our RASP solution, (coincidentally) solves this problem.
Just to give you an example, one of the most common security risks is reverse engineering. React Native apps are shipped as APK, AAB, or IPA files with the JavaScript code that is bundled with the application. This code can be, with a small effort of a person that knows what he is doing, easily extracted. Although the code is minified, there are utilities like that make it possible to unminify them and reveal your sensitive keys or API calls.
With a hybrid platform like React Native, the development of your application may cost less resources and time. That’s great! Unfortunately, you still have to solve platform-specific problems and focus on security on both iOS and Android. In addition to that, hybrid platforms may introduce new security flaws with adding more complexity to how your app is executed. And you don’t want to ignore them. If you want to keep your app safe, you can follow industry standards, such as .
When we started to think about extending our support to React Native at Talsec, we already had with protection for native Android and iOS apps, as well as other frameworks like Cordova and Flutter. The only challenging part was to understand how to create the bridge between native code and JavaScript, which would expose the freeRASP to the consumer, so you don’t have to spend your time messing around with native modules, testing and verification. We did all of this for you and are proud to introduce .
It’s quite simple, actually. Just follow the 4-step tutorial below. .
Furthermore, for Android apps you need to modify android/build.gradle to add our maven repository containing freeRASP. iOS requires Pods to run our plugin. Find out more .
| | Read also |
Part 2 () ↓
Part 3 () ↓
Back in the day, I had an opportunity to of mine whose app was hacked. He created a popular app called BetterVision for the blind and visually impaired. There was a good reason for the over 100K installations John’s creation has achieved. BetterVision provided a ground-breaking feature. It could turn a phone’s camera into a powerful assistant easing a daily routine for disabled users worldwide. With success, however, soon came difficulties. John’s app suffered a cloning attack, and his In-App purchases got stolen. Profits are now four times smaller because of cracked versions being still available. The attacker replaced In-App payments code with his payment gate!
or su allows you to modify app’s internal files
gives me a relatively simple way to sniff into the app’s process during its run. I can modify return values and inspect processed data
can disassemble app, and then I can modify the app and assemble it again
is Swiss knife with many analysis, reconnaissance, and disassembling tools. (must have!)
can repackage and mitigate common protections directly on device
is IDE for Frida with many useful scripts and monitors
or IDA PRO can create a readable code from app’s binary libs and modify the assembler
is the first Flutter-oriented reverse engineering tool necessary for MiTM attacks and binary inspection
's Interceptor mode to capture app’s network requests (typically JSON’s and raw data)
It’s nice to have a with a feature-rich file manager and terminal on board.
Alternatively, you can run it in Docker or check this online site (be careful, scan results are public!)
Let’t check this example. I created demo app using standard plugin. The app just increases the counter with value preserved in the Shared Preferences.
I promised this guide to be actionable, so here is the table of most common attacks and possible remediations. The rooting attack which can help attacker to steal sensitive data (and more) can be prevented by usage of the right anti-root or RASP solution (premium: , free: , basic: ). You will see more attacks in action in the next part :)
To create a fake or “cloned” version of an Android app using , you first need to decompile the original app using the apktool d command. This would extract the contents of the app, including its resources, manifest file, and compiled code, into a directory on your computer. Next, you need to make the desired modifications to the app, such as changing its name, icon, or functionality. Once the modifications are complete, you can use the apktool b command to rebuild the app into a new APK file. This APK file would contain the modified version of the app, which you could then install on an Android device.
To protect against these types of attacks, it’s important to implement proper input validation and sanitization, as well as keep backend web applications up to date with the latest security patches. Another method to mitigate the JSON injection attack is to ensure that API call comes from a legit client and not crafted by an attacker who may have valid authentication token. Talsec provides the technology to verify client-side legitimacy and integrity. In comparison with the similar Firebase AppCheck technology the can do this with every API call.
I will use the tool to break into an app and intercept it’s JSONs. The hacked app will reveal the content of its network traffic in the Burp proxy.
To inspect traffic using the Burp Interceptor proxy, you first need to set up on your computer and configure your testing device to use the Burp proxy. Once Burp is set up, you can use the Interceptor tab to view and manage incoming and outgoing traffic. The Interceptor tab displays a list of requests and responses, along with details such as the URL, method, headers, and payload.
A plethora of threats can be solved by a potent runtime application self-protection (RASP) library. There are various free solutions, but I have chosen the since it covers most areas, and I also contributed to this library.
I prepared a small demo below showing freeRASP’s checks triggered on a rooted emulator. However, you can process the threat flags as you need. From my experience, the most common way is to show a dialog to warn the user about a tampered app or device and forbid any sensitive operations. I also wrote about freeRASP in this previously.
Find out which security level (e.g., L1+R) is recommended for your app:
Try out freeRASP to get fundamental RASP features into your app:
However, there is still an opportunity for a hacker to strike — a compromised client application crafted for token stealing. Attackers can impersonate a legit application after stealing a token. The server cannot tell whether the legit application, compromised application or some other tool (e.g. , , …) is communicating with it. It just checks if the provided token is valid, fresh, and with proper scope (hint: a stolen token still is).
Remote Code Execution and Escalation of Privilege vulnerabilities are discovered all the time; see
App tampering is currently quite easy. Using proper tools (), you can decompile, modify and repackage the application. One only needs to entice potential victims into downloading a seemingly authentic application.
Despite best efforts, . With the rise of alternative stores and , you will likely find even more malware. Real-world examples could also be apps that promise you to gain some advantage or free versions of apps that you typically need to pay for.
If not, we recommend you give it a read, but in a nutshell — Firebase stores essential information in shared preferences. You can access and parse these data without any problem. And then misuse them in API calls.
In this part, we will mainly use . Apktool is a handy tool for reverse engineering of Android APK files. You can download apktool in the provided link.
Getting the format of the request is possible. For Flutter, you could use . A more general approach would be . With a bit of time, you will get a format of the POST request in our example app:
We can protect against this impersonation by adding an additional security control implementing the zero trust security model — . The zero trust assumes that all devices and applications cannot be trusted by default. Instead of relying on traditional security measures, zero trust employs a variety of security controls to authenticate and authorize devices and applications before granting access to protected resources. This aligns with the requirements from MASVS-RESILIENCE and MASVS-AUTH control groups.
You may have come across a similar technology Firebase AppCheck. We want to emphasize the significant difference between AppCheck and AppiCrypt. AppCheck is not applicable for every call but only during user enrollment. That means there remains space for token theft. It doesn’t prevent leakage but token issuance. We compared these technologies in the .
You can find more details about AppiCrypt on .
Flutter is a beautiful framework for building pretty and natively compiled mobile, web, and desktop applications. Thanks to its simplicity and developer-friendly way of building applications, it’s gaining popularity around the world. However, with great power comes great responsibility. As unlikely as it seems, Flutter applications face the same issues as their native siblings — security attacks.
The answer is yes, you should. Security engineering should always be your first step. The moment you take your development more seriously, security becomes your top concern. Whether you develop a simple attendance app or a demanding health, FinTech, or automotive application, you shouldn’t make any concessions in security, especially if you deal with personal data and/or finance transactions.
You could argue that reverse engineering of Flutter apps is not being done very often, and even if it is done, it’s complicated to get something. Your production build is compiled without debugging symbols, and compiled apps are usually harder to crack. Well, that’s true, for now. But first of all, this approach is nothing short of a hide and seek game — you will be caught, and time is playing against you. And second of all, complicated does not mean impossible.
Based on our experience, the following attacks are already possible:
App repackaging and cloning
Re-publishing of tampered apps
Running the App in compromised OS environments (rooted/jailbroken OS, hooking app during runtime, emulators)
Overlay and Cloak&Dagger attacks
Misuse of Accessibility Services
Stealing of hard-coded secrets
A common sign of intrusion on mobile devices is the presence of a root user. A root can do pretty much anything in the system. If we let our Flutter application work normally on a rooted device, we expose it to a possible attack/security breach just because the device’s state is compromised.
Applications need shields and swords to defend themselves — they need RASP (Runtime Application Self-Protection).
In Talsec, we noticed that RASP solutions at that time were not in good condition. We decided to do it our own way. And that’s how freeRASP was born — created to protect Flutter applications conveniently.
Cross-platform development frameworks, in general, suffer when platform-specific problems need to be solved. Sacrificing security to be able to do cross-platform development is a no-go. We already had experience with both native Android and iOS platform protection. The only question was how to do it for Flutter.
Luckily, in Flutter, you can expose native APIs. If you want to expose native API or implement a platform-specific library, you have to do the implementation for each platform separately. This means you have to understand the specifics of each platform — from low-level coding to system architecture specifics. You have to write a glue code between the native and Flutter side and some API to reuse implementation in other projects. Finally, you have to do tons of testing and verification. In a nutshell — long, cumbersome and exhausting process.
We decided to overcome this gap for you — we created freeRASP for Flutter. Our team did all the work you would typically need to do and shipped it to a pub.dev.
This had many positive effects:
made Flutter safer for everyone
contributing to the Flutter community by adding a plugin to pub.dev, which led to…
getting closer with the Flutter community so that we can listen to any opinion and making our product even better
We wanted to make Flutter safer because we saw its potential. The fast world needs fast development — that’s what Flutter does perfectly well. We also want to help Flutter grow so that more people can appreciate its advantages and raise awareness about security between Flutter developers. freeRASP is a real game-changer. The developer gets a nice and tidy plugin, and the user receives a secure application.
Implementation of freeRASP for Flutter is pretty simple. After initial importing, you just set up some initial configuration and callbacks. And that’s it!
From now on, freeRASP has your back covered and makes reports for you, so you have an overview of your application security. Make sure you accept an email confirmation request from the system to be able to receive these reports.
This example presents a mid-sized FinTech app:
You can find freeRASP for Flutter plugin on pub.dev. There is also a step-by-step guide to help you with implementation. If you like our plugin, don’t forget to give it a like.
Security is essential, even though we tend to forget about it when it comes to cross-platform applications. freeRASP provides a plugin for Flutter that solves this problem, and it’s easy to use. So what are you waiting for?
If you want to know more about freeRASP, don’t forget to bookmark these links:
Medium — article about freeRASP’s features
GitHub repository — main repository containing all necessary information
pub.dev — Flutter plugin
written by Jaroslav, Flutter developer at Talsec
Cybersecurity has been a global problem for several decades. However, we are still in a phase where the exponential growth of security exploits leads to significant financial losses for businesses and individuals.
The size of the cybersecurity market was $3.5 billion in 2004. It is approaching $150 billion in 2021 and is expected to reach USD 352.25 billion by 2026. Regardless of such tremendous investments in this domain, the overall situation with security seems to be getting worse. So why isn’t the vast number of available technical solutions solving the cybersecurity problem?
Ifwe ask an average technologically-minded manager in the security sector, we will get a simple answer. It is due to the low adoption of various brilliant tech solutions available on the market. Maybe… But isn’t this an over-simplified approach?
Suppose we want to radically improve cybersecurity and create a solution to gain mass user adoption. How would we get there? We must elaborate on the subject from different perspectives and go beyond the pure engineering view of security. Why?
One of the obstacles is that engineering-minded people tend to project the confusion in the problem statement onto users and explain the low adoption of security solutions by users’ ‘immaturity.’ On top of that, engineers quite often fall into an observation bias called the streetlight effect.
It is common for engineers to narrow the problem domain to a smaller segment that is more “comfortable” for research. They usually frame a problem, having in mind an “elegant” solution based on a “known” or “proven” technical framework. Meanwhile, the “core issue” may remain in the dark.
Technically minded people hate unclarity and vague problem statements. And it makes sense; we have to admit that otherwise, it is much harder to estimate and commit to the time needed for implementing the solution.
To tackle these problem statement misconceptions, we need to understand the difference between objective security issues and how users experience or perceive these problems. Remember the famous quote by Einstein “If I had an hour to solve a problem, I’d spend 55 minutes thinking about the problem and five minutes thinking about solutions.” Generally speaking, we can’t just leave the problem statement fully defined by engineering-minded people. We need to make sure that we address the root problems in the security domain and verify if the selected methods are relevant.
The best approach to combat biases and go to the core of the issue is philosophizing. For example, let’s take a closer look at security through the eyes of mobile app users.
Usually, the word “security” has a positive connotation for engineers. A good solution is a secure solution. Isn’t it so, dear CTOs?
While users often have ambivalent feelings about security, most have just run into too many unpleasant situations due to security measures. Have you ever blocked your payment card by incorrectly typing your PIN several times? Then you probably know how annoying security measures can be.
The core reason that security evokes negative feelings is that security, by definition, implies some limitations on freedom or privacy. It is especially true if an external party has imposed such limits out of our direct control.
NB: We may not realize it but people are quite used to being limited in freedom for the sake of security. For example, most of us were limited in our activities by our parents protecting us from the dangers of the external world. Another example is luggage scans in airports that somewhat intrude on our feelings of privacy.
There is often a “good reason” behind these limits, and it is communicated to users as a tradeoff between security needs and user convenience. But still, we often feel that it is unbalanced and doesn’t work how it should.
NB: Just think for a while how many potentially good online and offline services you have stopped using just because of annoying security measures.
The notion of safety is very close in meaning to security. But safety is subjective, i.e., a person can feel secure, in contrast to security, which is presumed to be a generic and objective concept. This difference explains why safety is perceived much more positively. The conditions leading to feeling safe are individual. Individual safety conditions may even contradict security conditions. And vice versa, security measures can conflict with and harm the feeling of safety. For some people, safety would mean accepting a certain comfortable level of insecurity, taking risks, and relying on self-protection skills. For others, it would mean the delegation of security to a trusted party and sacrificing some portion of personal freedom and privacy.
There is an essential implication in the subjective quality of safety. When we feel safe, it doesn’t necessarily mean we are objectively secure, and threats are absent.
Let’s sum up and list a few conclusions we have come to by now:
Security is not equal to safety; security measures are generic while the conditions of feeling safe are individual;
Security measures could harm the feeling of individual safety when an external entity manages it. In this case, security limits the users’ freedom and privacy that can go beyond the individual comfort zone.
Practically, users desire individual safety but may not have the full picture about security threats;
Engineers usually push generic security but have limited visibility into individual safety preferences and how security measures may impact them;
Both users’ and engineering’s views are influential and should be bridged and reconciled. Though, it is much easier said than done.
Many bright minds and philosophers have tackled the Freedom and Security dilemma from the ancient Greeks till modern times. The concept of the social contract was introduced and elaborated on in the 17th-18th century (Thomas Hobbes, John Locke, Jean-Jacques Rousseau). The social contract is an unwritten rule or agreement within the society that is supposed to balance and regulate the level of acceptable compromise between personal freedom and limitations for security provided by institutions, the state, or ruling classes.
In democratic states, citizens should influence this contract through the election process. Let’s assume for now that this mechanism works fine, and we have some control over the contract… I know some of you might say: it’s imperfect, it has a time lag, it is vulnerable to populism, but it still works, and we’ve got no better mechanism so far.
But what about social contracts in our digital life? We also delegate security to some external entities (consciously or not), don’t we?
Let’s use metaphoric language to highlight the parallels and differences between digital and real-life security in a simple thought experiment.
Let’s imagine people living in the digital world like a historical real-time strategy computer game, where every person is a “natural Intellect-driven” game unit. People are surrounded by wild nature and the circumstances of a middle-age period of human history. A very insecure place to live, isn’t it?
The people organized themselves and came up with a collective defense by creating fortresses in towns and dedicated security institutions. These institutions (like states) provided security services to citizens by building fortifications to protect them from enemies while limiting their freedom by introducing rules and taboos.
NB: Keep in mind that such security institutions always had a tendency to misuse the power of the function that they were delegated (security geeks would call this a bug in the system that leads to “elevation of privilege” due to an issue in the “segregation of rights”)
Initially, citizens could go straight to the marketplace. Now they are forced to go through the main gates, pass through some identity verification process, pay taxes, and so on.
Now let’s upgrade this imaginary world, and let’s say these people live in a Mobile Apps World, where every fortress-town is an App.
NB: It is actually not an oversaturated metaphor since people spend 80% of their average online time in Apps.
In reality, Apps are designed to be executed under the supervision of an operating system in a sandbox environment and isolated from other Apps and processes. In our imaginary App world, the operating system is like a state that governs the fortress towns (Apps).
The same as in real life, the protection of the basic set of citizens’ rights is regulated by such states (operating systems). But the actual level of security inside the fortress (App) is still designed by the fortress owners (App publishers). Let’s call them governors.
NB: There would be two dominant states with quite a different regime in our App world: the iOS Kingdom and Androidian Union.
Inhabitants of such a world can quickly jump over from one fortress to another within the state. They can sell products in the marketplace of eBay, keep their fortune in the Revolut fort, and fall asleep on the dirty streets of YouTube. Just like us.
In our imaginary App world, the fortress governors must take security very seriously since it is a matter of life and death in assumed middle-age conditions. Also, they are forced to take their citizens’ safety feelings even more seriously because it directly impacts the growth of the population, which is crucial for the economic success of the fortress-town.
Thus, the more financial resources a town has, the better security measures it can afford. So there is a positive feedback loop from users’ safety feelings to security. It doesn’t work vice versa. More severe security conditions harm the population growth, limiting freedom or causing too much discomfort. This is why it is always “safety first” in our imaginary App world in contrast to “security first” that we are pretty used to in our lives.
This also explains why governors can’t fully delegate the balance between security, freedom, and comfort to their subordinates (neither the army nor merchants ). It is an existential question for a given App that is just too important to be delegated. It is directly linked to the mission and economic model of the App fortress.
NB: Thus in the real world the safety strategy should form the “right” balance between freedom, security, and comfort for a given App. Top management shall define or at least arbitrate it. It can’t fully delegate it to marketing-minded or tech-minded subordinates.
These imaginary people of the App world have an advantage over us. They can visually observe the security system of fortresses that they consider entering. They can assess the security of the fortress app by a visual evaluation of the walls, gates, towers, or soldiers’ weapons and armor. These town citizens have the luxury of having an evident reason to trust the fortress app. And these citizens can easily guess how responsible and capable the owner of this town is in terms of security.
NB: In the real world, we usually lack clarity on how an app is secured. We only rely on the app review process of the marketplaces and trust in the given brand. This makes a strong link between trust in the brand and individual safety perception of the App.
Real-world App issuers rarely go the extra mile of guiding users through the security benefits of the app and user safety best practices. So users intuitively extrapolate the overall app UX quality to its security. As a result, any glitch in the App harms the feeling of safety just because users expect that security is at the same or worse level of quality as UX. The visual communication of security features, tips, and warnings could detach the perception of security from the rest of the functionalities. This aspect would be an independent factor of comparison with the competitors in the user’s eyes.
NB: The critical advantage of communicating and visualizing the state of App security is that it can help to bridge the gap between the personal feeling of safety and the actual state of user protection.
Security warnings and tips can be presented to only those users that have flaws in their device protection according to in-App protection controls.
NB: In-App protection is a mobile security technology that allows mobile applications to check the security state of the environment that it runs within, actively counteract attack attempts, and control the integrity of the App. Such technology is also called RASP (Runtime App Self Protection) or App-Shielding.
Let’s take a brief look at the Android security statistics collected from 400K devices of mBanking users (in EU countries). To get a general feeling of what percentage of users would deserve some security-related guidance, i.e., they have some fundamental security issues.
About 21% of users ignore the Screen Lock functionality. It exposes users to the risk of misuse of Apps and data breaches if the device is lost, stolen, or used by kids.
About 38% of users don’t use biometrics (like fingerprint scan), while only 12% (48K out of 400K) don’t have this feature available in their device; biometrics is much safer than a password or PIN. Incidentally, using a biometric lock doesn’t mean that data shared with any app or the device’s backend.
1112 users of 400K (0.28% have Rooted devices.). It means that the App integrity and its isolation sandbox can be compromised either through malware or by the user himself.
381 devices ran the App in a debugger mode, and 151 devices ran an emulator. These all are signals of a reverse engineering attack if they are not in the hands of a legal development team.
226 app instances have signs of app tampering (can indicate that the App was cloned, tampered, republished by an attacker, and a clone was installed).
Our imaginary governors know very well that an efficient defense should include more elements on top of the army and fortifications. Army and walls can probably protect from brute force attacks by barbarians, but it is much less efficient against traitors (aka fraudulent users in the real world), and can’t help against diseases caused by viruses (aka malware).
Fortress app owners could also realize that involving citizens in security affairs would increase the resilience of the town to large-scale problems while making the citizens more loyal and personally engaged.
That is why in the imaginary App world, governors should be very creative with educational activities, training, or performances explaining critical safety practices like how to detect scams and fraudsters, recognize suspicious activities of strangers, and hygiene rules to prevent epidemics.
So what I am pointing out is that businesses will implement user cybersecurity education and its visualization as an integral part of both the Security Journey and user loyalty programs soon.
NB: Some might say I don’t feel like educating my users about cybersecurity. Yes, it is quite a common view. I guess it was the same attitude among airline management before 1984. Since then, the pre-flight safety briefing has become mandatory and we are all quite used to watching the cabin crew demo every time we are about to take off.
Every fortress owner in our imaginary world would need to get alarm messages in case an enemy army approaches his fortress. None of the governors would dare to underestimate this subject. It should be easy for citizens to send a signal, “We are under attack!”. That is why alarm bells are placed on every screen square of the app fortress 🕭.
In our real-life FinTech apps, it is bizarre, but the “Report abuse” feature is often well hidden. As if app managers prefer “it’s better not to know” that there is a leak in the hold. The most common approach is “in case of emergency, call the Hotline and enjoy the IVR music” and let the call center sort out the issue.
Many FinTech mobile app issuers would say, “well, we have a modern risk scoring and monitoring system that collects many security signals from the app like location, behavioral data of users, and many more to estimate the risk of fraud.” Indeed, many Apps use risk-based security. But the main problem of risk scoring systems is they suffer from a lack of factual information about ongoing attacks. In other words, they miss the “source of truth” of what attack vectors look like.” Risk scoring logic usually is designed based on the best knowledge of the given security team about potential attack vectors. At the same time, the creativity of cybercriminals has a much higher speed, so attack methods are changing much quicker than risk scoring logic.
On top of that, a significant portion of attacks addresses the weakest link in the security chain — humans. So it is hardly identifiable by automatic signals. So the best we can currently do is detect the scam campaign from user reports and quickly find the appropriate method to prevent it from becoming a large-scale attack.
It is known that there is nothing more efficient against a common enemy than an alliance. In our App world, the governors of cities have much more chances of survival in the aggressive middle-age world if they join their efforts, i.e., form an alliance that implements the principles of a Collective Defense. The most crucial element in that collective defense is rapid information sharing about the enemy and how it is attacking.
In our real digital world, the quick distribution of detailed information about exploits is crucial (like malware binaries, scums, and zero-day vulnerabilities). In many cases, ML-driven mechanisms can automatically prevent many problems if they are trained by the “source of truth” information about the attack. Thus every reported attack can make the whole group more resilient.
It brings us to the question of which users would prefer to delegate the surveillance role and to who would they be happy to share the information about attacks? Is it governments, operating system vendors, device vendors, corporations like banks, small app issuers, professional communities, dedicated NGOs, etc.?
Let’s wrap up the takeaways of App security we touched on during this philosophizing exercise.
Safety first, not security. Safety is about making the “right” balance between freedom, security, and comfort. This topic can’t be fully delegated to marketing-minded or tech-minded middle management since it is a strategic brand development question.
App Security measures need to be visualized and explained for end-users to be perceived as safety elements and not just a security nuisance.
Engaging users in the Security Journey through educational content, gamification, and feedback (report issue), is an efficient way to gain loyalty and prevent many security-related problems.
Attack claims are a vital feature for building countermeasures. It should be simple and intuitive.
Consider joining the AppSec community to benefit and contribute.
Author: Sergiy Ykymchuk
Co-founder of Talsec (https://talsec.app.)
Mobile Apps Security Company
P.S.
Startups generally aim to change the world with their Apps and “make an impact” and influence people. The depth of our responsibility determines our actual influence. We are designing and manifesting our future influence by setting the boundaries of responsibility that we take.
Highly recognized freeRASP SDK providing app protection and threat monitoring for mobile devices arrived in the Cordova ecosystem! This article will help you understand runtime application self-protection, explore freeRASP capabilities, and shield your app against threats!
The popularity of hybrid platforms continues to grow, and companies have adopted them widely. They allow developers the possibility of writing the code once and reusing it on both Android and iOS native platforms. Often, the development of such apps costs less time and resources. Nowadays, there are many popular hybrid platforms (e.g., Flutter, React Native, Ionic, Cordova, or Xamarin).
Cross-platform development frameworks, in general, suffer when native platform-specific problems need to be solved and security has to be handled. In addition, hybrid platforms can introduce more specific issues. Sacrificing security to be able to do cross-platform development is a no-go.
“What should the developers do?”
First of all, ensure that the applications follow the standards for mobile app security (OWASP MASVS) for the native parts. Besides security requirements for the architecture, data storage, or network communication, the application should be secured with advanced security solutions such as runtime application self-protection (RASP) to protect against tampering, distribution via an unofficial way or the app being run in a compromised environment.
“But developing such solutions is quite expensive, right?”
Right, it is pretty expensive to develop it in-house. Luckily, there are companies which can handle the problem for you. Moreover, there are freely available solutions!
“What does freeRASP have to do with all of this?”
In the past, we have observed a strong growth in the popularity of Flutter and chose it as our first contact with cross-platform development. We looked at security issues of the Flutter apps and developed a freeRASP for Flutter, which has been a great success and the developers’ feedback vastly improved our product.
Since releasing a freeRASP for Flutter, there have been a number of developers asking whether we can support other platforms. While some of them have successfully integrated the native versions with some of the frameworks, there were problems using it with the Cordova framework. We decided to take a closer look and develop an easy-to-integrate plugin to make Cordova developers’ lives easier. And that’s how freeRASP for Cordova was born!
freeRASP for Cordova is a mobile in-app protection and security monitoring plugin. It aims to cover the main aspects of RASP (Runtime App Self Protection) and application shielding.
It is designed to combat:
Reverse engineering attempts (debugging, running in emulators, hooking)
Re-publishing or tampering with the apps
Running an application in a compromised OS environment (root/jailbreak)
Malware, fraudsters, and cybercriminal activities
“How can I use it?”
It is as easy as doing a minor prerequisite and adding a plugin to the application. Then you rely on freeRASP to protect your app. You can handle any threat that will be detected (e.g. attached debugger to the app) on your own, for example, by killing the application.
As Talsec uses Kotlin and Swift for the implementation of the native side, there is a minor prerequisite which must be done before adding the plugin.
Kotlin must be enabled, and the version must be set up in the config.xml file
A swift support plugin must be added
After that, you can easily add the plugin to your application. After initial importing, you set up an initial configuration (package name, signing certificate hash, bundleId, teamId) to have freeRASP detect some of the threats correctly. You also need to provide a mail address to which regular security reports will be sent.
Next, you define a threat listener function, in which you can handle the detected threats as you wish, for example, killing the application, notifying the user that a threat has been detected or just ignoring the threat. The threat listener:
freeRASP can be started after the Cordova initialization is completed. The initialization should be done inside the onDeviceReady function in index.js:
As the last step, you need to differentiate the dev and release versions of the library. The dev version is designed not to complicate the development process of the application (e.g. if you would implement killing of the application on the debugger callback). It disables some of the detections. On Android, it is handled automatically, whereas, on iOS, the step is a matter of adding a pre-built script into the run phases and embedding a symlink to the correct framework. Do not worry, it is quite easy ;)
freeRASP for Cordova is composed of freeRASP Android and iOS counterparts.
It contains a Gradle file, which contains the dependency for the Android freeRASP repository.
It also contains a TalsecPlugin.kt file, which provides the API to the freeRASP for communication with Cordova. It parses the configuration input given from index.js, registers the threat listener and starts the detection. If any threat occurs, it sends a message back to the index.js to the threatListener function. If any error or incorrect input occurs, it sends back an error message to the index.js.
It contains built binaries (both Debug and Release versions) of the freeRASP iOS library.
It also contains a bridging header for the Objective-C -> Swift bridge. The TalsecPlugin.swift file is similar to the Android’s TalsecPlugin.kt. Moreover, it uses a static object to preserve the state of the delegate given by Cordova for sending messages.
The iOS version also contains an after_plugin_add script to create a symlink to one of the built binaries (default is Debug) at the correct place. You guessed it right! This is the symlink used in the integration step, which is recreated after changing the Debug <-> Release build of the application.
It contains a simple Promise, which passes the configuration from index.js to respective native implementations and returns back a success or error message.
The plugin is designed to be used easily without the modification of the native parts. The reactions to threats can be modified in the index.js easily in the threat listener, and configuration is also passed from index.js.
However, you can set up the configuration, threat listener and initialisation also from the native parts and not interact with index.js at all, for example, if you would prefer using a “native way” of killing the application.
We have prepared a simple demo application which integrates the plugin. It shows the state of the threats with simple visualisation: green: OK, red: NOK (a threat happened). The threat listener is implemented in index.js. If a threat is detected, it changes the backgroundColor of the element corresponding to a given threat to red colour.
Except for the GitHub repo, the plugin is also distributed via NPMJS: https://www.npmjs.com/package/cordova-talsec-plugin-freerasp
Security is essential, even though we tend to forget about it when it comes to hybrid platform applications. However, the freeRASP solution is not bulletproof.
In the freeRASP, it’s up to the developer to implement the reaction for the individual threats (e.g., root, debug, simulator, device binding), and because each developer can implement their own logic for detected threats (e.g., step-up authentication, business logic flow modification, killing the application), we need to provide API for the callback, so they can implement their own logic.
The javascript part of the application tends to be more vulnerable to manipulation/injection/tampering, and it would be better to start Talsec in the native part of the code. However, even the reaction on the native side can be easily modified or stripped by an experienced attacker.
We have multiple solutions (pre-configured custom build SDK, in-SDK reactions and killing mechanism, AppiCrypt) in our business solution, preventing precisely those types of attacks. To check out what is the difference between freeRASP and Business RASP+, see this page: https://github.com/orgs/talsec/discussions/5
written by Matúš Šikyňa, Developer at Talsec
https://talsec.app | info@talsec.app | Read also 5 Things John Learned Fighting Hackers of His App — A must-read for PM’s and CISO’s | Mobile API Anti-abuse Protection: AppiCrypt® Is a New SafetyNet and DeviceCheck Attestation Alternative
John is the creator of a popular app BetterVision, for the blind and visually impaired. There is a good reason for the over 100K installations John’s creation has achieved. BetterVision can turn a phone’s camera into a powerful assistant easing a daily routine for disabled users worldwide. With success, however, soon came difficulties. John’s app suffered a cloning attack, and his In-App purchases got stolen.
At Talsec, we specialize in in-app security. We build RASP (Runtime Application Self-Protection) tools to protect apps against hacking — which, unfortunately, is growing in popularity. In this article, we interviewed Business Owner and senior Android developer John Smith whose app BetterVision got hacked. The interviewee has requested anonymity. We deliberately changed his name to “John Smith” and his brand name to “BetterVision”.
Do not release without protections in-place
Perform sensitive operations server-side whenever possible
Prevent reverse-engineering
Monitor user groups and APK mirroring sites to detect malicious clones
Warn users against using fake clones
My five tips are:
Using time-saving drop-in solutions like Talsec and not messing up security basics pays off. Otherwise, you have to accept losing some percentage of purchases due to hacked clones and take it into account — also financially. I remember an Android security survey that suggested that most apps lack even the most basic obfuscation.
It can sound silly, but the thing is that when you have to choose between delivering functionality and improving security, you should select the first and reckon with the risk. I have heard of companies focused on security so much that they could not develop the functionality needed for business.
My Firebase catches something already, but I would appreciate Talsec’s monitoring as it is more advanced. It would be great to see the collected statistics.
I had the warning screen displayed in hacked clones that exited the application only to realize users of clones began complaining and giving bad reviews. So, I later reverted it as it wasn’t worth it. However, I believe it’s good to have hidden logging, which can’t be disabled by a hacker easily. That’s what I finally ended up with. The hacked clones still report to my monitoring service as hackers apparently don’t care about that.
Yes, it would be necessary to add a lot of arbitrary fake reflection calls so that the important ones will be hidden between them. These could also serve as a kind of honey-pot. I would appreciate a plugin that would perform this transformation automatically.
Obfuscation is of great importance in hiding inner business logic. You can combine obfuscation with the reflection API to hide system calls. Hackers often head for them as these are usually placed close to sensitive operations. With reflection, you turn these calls into strings that are consequently obfuscated. Hackers will not be able to locate them using static analysis. Unfortunately, hackers are aware of this technique, and if you use it only on a few occasions, they can easily guess its meaning.
It’s a cat-and-mouse game. Hackers always find your protections, so you are forced to evolve your knowledge and update your app. For example, I spread those checks into many places in the app, so they are more likely to forget something untouched.
As I said, the first choice for me was the PiracyChecker as Talsec was not a thing back then. I have learned a lot from experienced Android developers on advanced forums. Things like decentralizing security checks, hiding secrets in a native code, rooting and tampering protection.
The common issue of established RASP libraries is that bypass for the majority of them is already publicly available. I feel the Talsec has a slight edge in this manner, at least for now.
I didn’t have the necessary knowledge at that time. I have added the popular PiracyChecker library (note: Talsec didn’t exist at that time), but hackers still could circumvent it. As I have learned more about protecting Android apps, I have added many protections myself later. Alas, the iOS version of my app still needs to enhance the protection, which falls behind the Android one.
RASP made by Talsec does come as a complete toolbox of security enhancements. Reverse engineering protection can protect your app with many invisible traps that give hackers a hard time. Malware detection, tapjacking prevention, E2E Encryption, mutual TLS setup, online client integrity checks (Attestation), On-line Risk Scoring, API protection, Strong Customer Authentication, embeddable security dashboard, and much more are covered in our enterprise security. Contact us for a private meeting!
It’s common to use native code for hiding valuable parts of an application as its decompilation of binary is a much more demanding task. I hide logging and security checks in various places. There’s a high probability a hacker will miss some parts, and you will be able to track malicious activities. A hacker only aims for the functional clone and doesn’t care about making it top-notch in the end.
Not necessarily; you can change a Proguard’s dictionary. The unfortunate side effect is that Google Play’s review process becomes more time-consuming. The regular one-day review process takes up to 10 days if you change the dictionary, as Google Play scanning is more thorough in such cases. If I need to push hotfixes quickly, I stick with the same dictionary as my previous build.
Finally, strip out any debugging lines. Popular library Timber has one crucial weakness regarding that. Although your Timber tree won’t log in the production build, your debugging code is still in place. A hacker can just turn debugging on for the app, and the logging will be visible again. Creating your logging scheme is also beneficial. Debug and verbose logs are dropped in production, informational logs are written into the local log, and finally, warnings and more severe events are logged to Firebase.
I highly recommend the string obfuscator Paranoid. It only takes a single annotation @Obfuscate above the class, and you are good to go.
I remember having issues with code obfuscation. In some cases, older versions of Proguard (code obfuscator) obfuscated method parameters but created annotations with original names above them. I haven’t noticed such issues with R8, which ships with Android Studio nowadays.
“A hacker only aims for the functional clone and doesn’t care about making it top-notch in the end.”
For example, there was a guy from India who even added his own payment system and he charged half the price of the original. He even went to great lengths in protection and used a DexGuard to protect it. We got a hold of his WhatsApp and phone number. We unsuccessfully tried to sue him, but he was out of our legal reach.
Although they don’t usually want to talk to us, there was a white-hat guy who appreciated our work and gave us a few hints as to what we might do better. Apart from that, they only care about adding their own ads and other nasty things.
Hackers are still active and create new clones. They can often release a clone just a few days after our updates. Unfortunately, we don’t have any way to disable those cracked versions.
There were also videos on YouTube that contained links to clones. Reporting to Google (Content ID claim) worked well. Google took down the incriminated video within a day. Reporting links to Google Drive with hacked versions was also successful.
Yes. The community was very supportive. Community members send us links to hacked versions. Fans are also sending in recordings of communications with the attackers. We’re tracking it, and we have a whole database full of it.
A common tool used for hacking is the app called Lucky Patcher. So I added a detection which caused the app to stop if the user had it installed. It turned out that many people have Lucky Patcher installed, and after an avalanche of complaints by angry users, I reverted this detection.
The first versions contained only basic functionality. In retrospect, I have to say that launching the app without protection was a big mistake. It was only in response to the hacking that the first protection was added, which was a signature check. This stopped cloners and amateurs from using automated repackaging tools for a while. A little later, I also added the string obfuscation.
If you find out that you have four times more users on Google Play than on the AppStore and your profits are four times less, something is fishy. Sideloading of cracked apps, simplicity of rooting, and APK modifications are significant drawbacks of the Android platform. iOS protects both users and developers better against such malicious activities. A profitability perspective is much better as users are better used to paying for apps.
Although we haven’t done the math, the financial losses are significant. Because hackers may have disabled the in-app tracking, the actual number of installed cracked clones cannot be determined. Although Android has four times as many users as iOS, profits are four times smaller because of cracked versions being still available.
It was a terrible feeling considering I used to develop it in my spare time for almost no profit initially. The application fee was only enough to cover the costs. Later, we invested a fair amount of money for performant Amazon servers used for machine learning.
I think that some users were resourceful and hacked the app themselves by removing Google Play Billing Library in-app purchases. As long as they were doing it for their own use, I didn’t even mind.
Users themselves reported finding illegal copies, which started popping up on Telegram and WhatsApp groups. Anyone could grab those APKs and install them. Paid users were upset.
“Although Android has four times as many users as iOS, profits are four times smaller because of cracked versions being still available.”
We immediately had positive feedback from users after the release. We were amazed that users even switched from a competing app to us. We made it into newspapers and TV in the homeland thanks to great help from local organizations. We recruited ambassadors from the ranks of users in foreign regions.
Getting early-stage traction was surprisingly easy thanks to the strong disabled communities in which our app quickly gained attention. Users recommended the app to each other, especially coaches for disabled people, who took the initiative and spread the word among clients.
Oftentimes, in reality, it is not possible to host valuable assets from the cloud safely, and you must put them into the app.
Finally, ease of use and accessibility required offline operation because users don’t always and everywhere have a good network connection. One of the cornerstones and our know-how are computer vision models using machine learning. These have to be a static part of the application since users might have issues if they were hosted on the cloud. It is one of the misconceptions many developers have. They believe they can secure everything by putting it server-side. Oftentimes, in reality, it is not possible to host valuable assets from the cloud safely, and you must put them into the app.
The idea wasn’t novel as there already were similar solutions by renowned companies. We kicked off with only basic features at the beginning focusing on accessibility. Not only we thoroughly tested eyes-free usage in the app but also accompanying web and brochures. I regularly tested it myself, covering my eyes with my hand.
The idea came from a disabled friend. Together we realized this is a widespread issue which many disabled people face. Similar solutions already existed but were insufficient (school projects) or with poor accessibility optimizations.
The idea came from a disabled friend. Together we realized this is a widespread issue which many disabled people face. Similar solutions already existed but were insufficient (school projects) or with poor accessibility optimizations.
The idea wasn’t novel as there already were similar solutions by renowned companies. We kicked off with only basic features at the beginning focusing on accessibility. Not only we thoroughly tested eyes-free usage in the app but also accompanying web and brochures. I regularly tested it myself, covering my eyes with my hand.
Finally, ease of use and accessibility required offline operation because users don’t always and everywhere have a good network connection. One of the cornerstones and our know-how are computer vision models using machine learning. These have to be a static part of the application since users might have issues if they were hosted on the cloud. It is one of the misconceptions many developers have. They believe they can secure everything by putting it server-side. Oftentimes, in reality, it is not possible to host valuable assets from the cloud safely, and you must put them into the app.
Oftentimes, in reality, it is not possible to host valuable assets from the cloud safely, and you must put them into the app.
Getting early-stage traction was surprisingly easy thanks to the strong disabled communities in which our app quickly gained attention. Users recommended the app to each other, especially coaches for disabled people, who took the initiative and spread the word among clients.
We immediately had positive feedback from users after the release. We were amazed that users even switched from a competing app to us. We made it into newspapers and TV in the homeland thanks to great help from local organizations. We recruited ambassadors from the ranks of users in foreign regions.
“Although Android has four times as many users as iOS, profits are four times smaller because of cracked versions being still available.”
Users themselves reported finding illegal copies, which started popping up on Telegram and WhatsApp groups. Anyone could grab those APKs and install them. Paid users were upset.
I think that some users were resourceful and hacked the app themselves by removing Google Play Billing Library in-app purchases. As long as they were doing it for their own use, I didn’t even mind.
It was a terrible feeling considering I used to develop it in my spare time for almost no profit initially. The application fee was only enough to cover the costs. Later, we invested a fair amount of money for performant Amazon servers used for machine learning.
Although we haven’t done the math, the financial losses are significant. Because hackers may have disabled the in-app tracking, the actual number of installed cracked clones cannot be determined. Although Android has four times as many users as iOS, profits are four times smaller because of cracked versions being still available.
If you find out that you have four times more users on Google Play than on the AppStore and your profits are four times less, something is fishy. Sideloading of cracked apps, simplicity of rooting, and APK modifications are significant drawbacks of the Android platform. iOS protects both users and developers better against such malicious activities. A profitability perspective is much better as users are better used to paying for apps.
The first versions contained only basic functionality. In retrospect, I have to say that launching the app without protection was a big mistake. It was only in response to the hacking that the first protection was added, which was a signature check. This stopped cloners and amateurs from using automated repackaging tools for a while. A little later, I also added the string obfuscation.
A common tool used for hacking is the app called Lucky Patcher. So I added a detection which caused the app to stop if the user had it installed. It turned out that many people have Lucky Patcher installed, and after an avalanche of complaints by angry users, I reverted this detection.
Yes. The community was very supportive. Community members send us links to hacked versions. Fans are also sending in recordings of communications with the attackers. We’re tracking it, and we have a whole database full of it.
There were also videos on YouTube that contained links to clones. Reporting to Google (Content ID claim) worked well. Google took down the incriminated video within a day. Reporting links to Google Drive with hacked versions was also successful.
Hackers are still active and create new clones. They can often release a clone just a few days after our updates. Unfortunately, we don’t have any way to disable those cracked versions.
Although they don’t usually want to talk to us, there was a white-hat guy who appreciated our work and gave us a few hints as to what we might do better. Apart from that, they only care about adding their own ads and other nasty things.
For example, there was a guy from India who even added his own payment system and he charged half the price of the original. He even went to great lengths in protection and used a DexGuard to protect it. We got a hold of his WhatsApp and phone number. We unsuccessfully tried to sue him, but he was out of our legal reach.
“A hacker only aims for the functional clone and doesn’t care about making it top-notch in the end.”
I remember having issues with code obfuscation. In some cases, older versions of Proguard (code obfuscator) obfuscated method parameters but created annotations with original names above them. I haven’t noticed such issues with R8, which ships with Android Studio nowadays.
I highly recommend the string obfuscator Paranoid. It only takes a single annotation @Obfuscate above the class, and you are good to go.
Finally, strip out any debugging lines. Popular library Timber has one crucial weakness regarding that. Although your Timber tree won’t log in the production build, your debugging code is still in place. A hacker can just turn debugging on for the app, and the logging will be visible again. Creating your logging scheme is also beneficial. Debug and verbose logs are dropped in production, informational logs are written into the local log, and finally, warnings and more severe events are logged to Firebase.
Not necessarily; you can change a Proguard’s dictionary. The unfortunate side effect is that Google Play’s review process becomes more time-consuming. The regular one-day review process takes up to 10 days if you change the dictionary, as Google Play scanning is more thorough in such cases. If I need to push hotfixes quickly, I stick with the same dictionary as my previous build.
It’s common to use native code for hiding valuable parts of an application as its decompilation of binary is a much more demanding task. I hide logging and security checks in various places. There’s a high probability a hacker will miss some parts, and you will be able to track malicious activities. A hacker only aims for the functional clone and doesn’t care about making it top-notch in the end.
RASP made by Talsec does come as a complete toolbox of security enhancements. Reverse engineering protection can protect your app with many invisible traps that give hackers a hard time. Malware detection, tapjacking prevention, E2E Encryption, mutual TLS setup, online client integrity checks (Attestation), On-line Risk Scoring, API protection, Strong Customer Authentication, embeddable security dashboard, and much more are covered in our enterprise security. Contact us for a private meeting!
Did you consider products like Talsec RASP or freeRASP?
I didn’t have the necessary knowledge at that time. I have added the popular PiracyChecker library (note: Talsec didn’t exist at that time), but hackers still could circumvent it. As I have learned more about protecting Android apps, I have added many protections myself later. Alas, the iOS version of my app still needs to enhance the protection, which falls behind the Android one.
The common issue of established RASP libraries is that bypass for the majority of them is already publicly available. I feel the Talsec has a slight edge in this manner, at least for now.
As I said, the first choice for me was the PiracyChecker as Talsec was not a thing back then. I have learned a lot from experienced Android developers on advanced forums. Things like decentralizing security checks, hiding secrets in a native code, rooting and tampering protection.
It’s a cat-and-mouse game. Hackers always find your protections, so you are forced to evolve your knowledge and update your app. For example, I spread those checks into many places in the app, so they are more likely to forget something untouched.
Obfuscation is of great importance in hiding inner business logic. You can combine obfuscation with the reflection API to hide system calls. Hackers often head for them as these are usually placed close to sensitive operations. With reflection, you turn these calls into strings that are consequently obfuscated. Hackers will not be able to locate them using static analysis. Unfortunately, hackers are aware of this technique, and if you use it only on a few occasions, they can easily guess its meaning. Agreed. The reflection is easily spotted in the code. Do you have any solution in mind?
Yes, it would be necessary to add a lot of arbitrary fake reflection calls so that the important ones will be hidden between them. These could also serve as a kind of honey-pot. I would appreciate a plugin that would perform this transformation automatically.
I had the warning screen displayed in hacked clones that exited the application only to realize users of clones began complaining and giving bad reviews. So, I later reverted it as it wasn’t worth it. However, I believe it’s good to have hidden logging, which can’t be disabled by a hacker easily. That’s what I finally ended up with. The hacked clones still report to my monitoring service as hackers apparently don’t care about that.
My Firebase catches something already, but I would appreciate Talsec’s monitoring as it is more advanced. It would be great to see the collected statistics.
It can sound silly, but the thing is that when you have to choose between delivering functionality and improving security, you should select the first and reckon with the risk. I have heard of companies focused on security so much that they could not develop the functionality needed for business.
Using time-saving drop-in solutions like Talsec and not messing up security basics pays off. Otherwise, you have to accept losing some percentage of purchases due to hacked clones and take it into account — also financially. I remember an Android security survey that suggested that most apps lack even the most basic obfuscation.
My five tips are:
Do not release without protections in-place
Perform sensitive operations server-side whenever possible
Prevent reverse-engineering
Monitor user groups and APK mirroring sites to detect malicious clones
Warn users against using fake clones
written by Tomáš Soukal, Mobile Dev and Security Consultant at Talsec
JWT Token, MiTM Attacks and API Protection. Keep them properly protected and don’t put your enterprise at risk.
Part 1 (link) ↓
Disassemble app.
Extract its secrets.
Part 2 (link) ↓
Make a fake clone.
Check every transmitted JSON.
Inject code.
Part 3 (this article) ↓
Steal authentication tokens.
and attack the API.
A token is a piece of data that represents a specific identity or authorization. There are different types of tokens, including authentication tokens, which are used to authenticate a user’s identity, and bearer tokens, which grant access to a protected resource.
JWT, or JSON web tokens, are types of tokens used for authenticating and authorizing users. These tokens are encoded and signed, allowing the server to verify their authenticity. However, JWT tokens can be vulnerable to certain attacks, such as weak token signing and token tampering.
Weak tokens are tokens that have been compromised or are otherwise insecure. This can include tokens with weak or easily guessable signing keys, or tokens that have been stolen or otherwise obtained by an attacker. These weak tokens can be used to gain unauthorized access to a system or a protected resource.
The JWT standard allows the non-use of an algorithm (”alg”:”none”) to sign the token. This is of course a very bad practice. A user could change his rights on the fly (from “role”: “user” to “role”: “admin”), without any control by the server. In the same way, if the configuration carried out at the server level accepts different algorithms and the “none” variable, which consists of not having cryptographic functions, it will be possible for an attacker to bypass the integrity verification function to access the data of other users or even of the admin. This can be mitigated by choosing a reliable algorithm (SHA256) and force server to always check algorithm, and therefore reject the “none” variable.
Firebase Authentication is Flutter Apps’ most favorable authentication service. It allows developers to easily integrate user authentication into their applications using a variety of authentication methods, such as email and password, phone number, or social media accounts like Google, Facebook, and Twitter.
When a user signs up for an account using Firebase Authentication, the service generates an authentication token that is associated with the user’s account. This token is then stored on the user’s device and is used to verify their identity whenever they access the application.
When the user attempts to log in to the application, the authentication token is sent to the Firebase Authentication server, where it is verified and then passed back to the application. If the token is valid, the user is granted access to the application.
Now, if you’ve read the previous section carefully, you already know what we are after:
This token is then stored on the user’s device…
I want to emphasize that storing this token is a completely appropriate solution assuming the device’s sandbox and other security measures are intact.
This hello-world Flutter app is connected to Firebase Authentication. A few widgets, some copy-pasting from the Firebase tutorial, and it was up and running:
Once I registered my new account, I checked the account exists as well in Authentication Dashboard:
Everything works well, I am signed in
Sorry, I won’t show you any zero-day vulnerability. I assume there is a vulnerable system at play or a malicious 3rd party library (yes, 3rd party dependencies can interfere with app’s data and more), which will steal data from within your application.
Locate the app’s data directory /shared_prefs
, which contains a file named com.google.firebase.auth(…)
.
The file has the following content:
I moved the content to my computer for easier manipulation. The highlighted text is Firebase Authentication JWT:
TIP: You can use fancy JWT viewer — jwt.io:
And here is the data:
An attacker could misuse this token for an impersonation attack. But to be able to make such an attack, it’s necessary to know the API. Let’s explore the API of the Flutter app.
An API attack is a type of cyberattack in which an attacker exploits vulnerabilities in an API in order to gain unauthorized access to sensitive data or systems.
Here are some examples of how a reverse engineer might carry out an API attack:
Sniffing: The attacker captures network traffic containing API requests and responses in order to extract sensitive information such as passwords or access tokens. This can be done using tools like Wireshark or Burp Suite.
Injection: The attacker modifies the API request in order to inject malicious code into the system. This can be done using techniques like SQL injection or cross-site scripting (XSS).
Tampering: The attacker modifies the API request in order to alter the data being transmitted, such as changing the value of a transaction or account balance.
Replay: The attacker captures a valid API request and then replays it multiple times in order to cause a denial of service (DoS) attack or gain unauthorized access to the system.
These are just a few examples of API attacks that a reverse engineer might carry out.
To attack the API of a mobile app, a reverse engineer would need to first identify the API and its associated vulnerabilities. This can typically be done by using a tool to intercept network traffic from the mobile app and analyzing the requests and responses to and from the API.
Once the API has been identified, the reverse engineer can attempt to exploit any vulnerabilities that are found. For example, if the API is not properly validated or sanitized, the reverse engineer could try injecting malicious code into the request in order to gain unauthorized access to the system or steal sensitive data.
Other tactics that might be used in an API attack on a mobile app include tampering with requests in order to alter data, capturing and replaying requests in order to cause a denial of service (DoS) attack, and sniffing network traffic to extract sensitive information.
strings — You can use strings
command available in many Linux distros to gather string resources from any Flutter app:
$ strings my-flutter-app.apk | grep http
to gather URLs
GraphQL architecture — You can find GraphQL queries in the app’s binary
REST architecture — You can use strings
or Burp Proxy (MITM) again. Common APIs can be found here. The web service may also have it’s OpenAPI (Swagger) documentation available.
I decided to end this article here as there is a plethora of API hacking tutorials: https://duckduckgo.com/?q=api+hacking+burp+postman
Check of your Firebase is properly configured: https://github.com/MuhammadKhizerJaved/Insecure-Firebase-Exploit
Glance over the Resources section of this article and check out one of the provided cheatsheets (the most relevant to your app)
IMPORTANT: Majority of network attacks (impersonation, malicious scripts, botnets, JWT stealing, etc.) can be defeated by Talsec’s unique technology AppiCrypt. Check it out!
Thank you for reading the third part of this guide. I hope the information I’ve provided has been useful and informative! Thank you again for joining me on this journey.
written by Tomáš Soukal, Security Consultant at Talsec
It would be impossible to provide tutorial for every possible mobile app + web service architecture. Hence, I compiled useful list of OWASP and other resources about web application security. Use the list below to find quickly technologies and guides related to your use-case.
Firebase security checklist
Misconfiguration of Firebase — world readable https://xyz.firebaseio.com/.json
Exploit tool for this vulnerability:
A simple Python Exploit to Write Data to Insecure/vulnerable firebase databases! Commonly found inside Mobile Apps. If the owner of the app have set the security rules as true for both “read” & “write” an attacker can probably dump database and write his own data to firebase db. Control Access with Custom Claims and Security Rules | Firebase Authentication
Verify ID Tokens | Firebase Authentication
Recently published content from TALSEE, our external guest experts, and Talsec Originals, our in-house engineers.
Himesh Panchal
I’m a passionate web and tech enthusiast who has been working with Flutter since its 1.0. I specialise in optimising mobile app CI/CD workflows and enjoy writing technical articles to share my knowledge with the developer community. When I’m not coding, you’ll likely find me hiking in the mountains and connecting with nature.
Marco Galetta, Senior Software Engineer
Experienced and dedicated Mobile App Developer with impressive expertise in Flutter Framework. Directs the design, development, and implementation of mobile applications and delivers products ahead of schedule.
A Brazilian Software Engineer specializing in native Apple technologies and Flutter development. Skilled in project leadership, open-source contributions, and developer mentorship. and
,