After a long time of silence, today I'm going to write a different kind of article about using the wrong technologies for the wrong purposes. Not every modern technology is meant to be used wherever a developer wants. While some technologies have strengths in certain areas, others may not. Therefore, developers should be responsible for using technology correctly. To explain this, I will use a real-world example where a technology was misused.
First of all, I'd like to announce that I have created a brand name, or more specifically, a Facebook page, to offer my freelance services to local clients. On that page, I often post these kinds of true stories. I took this story from my own Facebook page and rewrote it to fit my personal website. This is my formal portfolio after all. Without going off topic, let's get into it.
This story begins with a website that I found on Facebook. As I observed, it was written by a solo developer. As a security researcher, I like to analyse software developed by solo developers because they often leave security flaws more frequently than well-structured agencies. While projects go through many layers in agencies, it's natural for solo developers to leave doors open due to a lack of security testing. There's no shame in that though. Solo developers do a huge amount of work on both the development and deployment sides. That workload may sometimes exhaust them and sometimes limit them in certain areas. On the other hand, security researchers aren't limited like that. They think outside the box because their only job is to find security flaws.
Let's get back to this application. Honestly, I didn't see any serious issues with this website. The back-end is well written, properly authenticated, and so on. So this solo developer did a very good job there, except in one case. While I was analysing it, I found a minor security issue, something I didn't expect. So I thought it was worth talking about. It also violates the website's data security policies. Therefore, I thought it should be mentioned.
This is an overengineered application in my opinion. Overengineered in a particular way. Let me explain its high-level architecture so you can understand the flaw better.
This website has two main components, so it is not written using a monolithic architecture, but rather a client-server architecture. The server and client communicate via the Hypertext Transfer Protocol (HTTP). The developer used JSON Web Tokens (JWTs) generated by the Google Identity Toolkit API to secure these messages. So there's no issue there at all. However, these JWTs are required only for authenticated HTTP requests made by logged-in users. So a question arises here. Are the other endpoints not secure? Not at all. This is where the overengineering happened.
For this specific case of securing unauthenticated HTTP requests, the developer used an interesting approach. They used a WebAssembly module. As a security researcher, that immediately caught my attention. I was eager to decode it to see what secrets were hidden inside. I must confess that even though I could see those unauthenticated HTTP requests, I couldn't initially find a way to reproduce them. The developer used a JWT to secure them, and I couldn't determine where it was being generated. I spent hours in the browser's developer tools because the developer had obfuscated the relevant JavaScript code. However, in the end, I found it. I found the WebAssembly module, which had been renamed to something else, a name no one would think of, along with the obfuscated JavaScript code that bridged the WebAssembly module with the browser.
I noted this as a classic example of security through obscurity, something amateur developers and non-technical people in organisations often rely on. Here are the developer's main mistakes.
The first mistake is that the developer thinks no one can reverse-engineer the obfuscated JavaScript code, which is completely false. It may be true for general users and even some developers. But for an attacker or a security researcher, it is only a matter of time. They have ways to understand application logic and flaws that others do not. It's a classic example of security through obscurity.
The second mistake is thinking that WebAssembly is good for security. The developer was mistaken again. Decoding a WebAssembly module is even easier than reverse-engineering obfuscated JavaScript code. In most cases, it's just one command away. It's another example of security through obscurity.
In this particular case, the developer used Rust to implement this custom cryptographic implementation. They exposed the algorithm, the JSON template used to generate the JWT payload, the hash salt for the secret key, the specific crates used in the program along with their versions, their operating system (OS), local time, and local username. They also exposed parts of the internal filesystem structure. That JSON template and hash salt were hardcoded into the WebAssembly module. This kind of information can be very useful for targeted attacks. The program was compiled into a WebAssembly module and bridged to the browser using a popular JavaScript library. That bridging logic was written in JavaScript, and the developer obfuscated that code.
I believe this mistake happened not because of a lack of knowledge or practice, but because overengineering made the developer unaware of certain security boundaries. After all, this is a website. No one needs to reverse-engineer anything. Just one or two lines in the browser's developer console can create the exact same JWT, and anyone can use it to abuse the application's internal API endpoints. With a library like Deno, you can even build a separate client for this specific back-end. It's possible because the developer didn't harden the API at all. In short, this developer forgot every fundamental because of modern technologies like WebAssembly.
Someone may argue that this is not a severe issue. I may agree with them. Even the developer argued that after I sent a private vulnerability disclosure. They also said it was not intended for security but to prevent copycats. I thought, "Was it? A fancy approach though," but never said it. However, their data security policy states otherwise. It says this was a front-end-based security mechanism to protect users' data. So they claim they considered it a proper security mechanism, while at the same time saying it was merely a deterrent against copycats. I simply stopped arguing and moved on. But in my own thoughts, I said, "WebAssembly is not for creating security barriers, but for creating speed bumps. So use it with that in mind." However, they have violated their own policies, and users still use the application without being aware of it.
The core problem is not whether that API or its data is valuable, but the delusion many developers have these days. This is not the only case I have observed. I have seen many cases where developers overengineer their applications with fancy technologies, forget the basics, leave OWASP API Security vulnerabilities everywhere, and so on. I believe many developers are deluded by their technology stacks. Fancy MERN- or PERN-like stacks hide API calls beneath the surface, so average developers don't tend to think about them, and Google Identity Toolkit provides authenticated JWTs, so many developers assume they are secure simply because Google generates them, and so on. The real problem lies there. Most developers have become users of tools rather than software engineers nowadays. With that thought, I conclude this article.