Over the past two years, I have been working to secure a suite of sites belonging to a global enterprise. Along the way I have learned (and been taught) many lessons I would like to share, but we need a solid foundation before we dive down the rabbit hole. This post will cover the basics that you will find in dozens of other posts, but I’m not stopping here.
My focus has been on web application and API security, but most of the workflow is the same when working with desktop/mobile applications. Some of the tools will be different, but we’re logically hunting for the same kinds of abuse. Feel free to reach out with feedback or ideas. I don’t bite.
Ensuring that the code being written is high quality and doesn’t introduce security issues is arguably the most difficult ask in application security. It is essential to try, but failures are almost inevitable. Even with the advent of agentic AI assisting with code reviews, it isn’t enough to prevent security bugs from making their way into production. The good news is that the code doesn’t have to be perfect if your compensating controls are good enough to make up for it.
This is where most application security programs focus their efforts. If you go looking elsewhere for application security advice, you’re likely to see a lot of discussion around the topics above and not much else. This might be a result of their being more developers with CISSPs than hackers with IDEs, but I could be wrong about that. The work being done at this level is important, and most likely has the best rate of return in terms of security posture. That being said, there is a lot more work to be done that typically flies under the radar.
This is where I spend most of my time, and from what I have seen is the least talked about side of application security. The cloud team handles IaC and patching, the penetration testers handle DAST, and nobody has looked at the WAF in six months. Meanwhile, there are security issues that would be obvious if anyone on the application security side cared to look at any of these things.
My application security journey started with an alert regarding an ongoing credential stuffing attack. From there, I took a look at the request logs and noticed the login endpoint was being hammered with requests. At that point in time, a CAPTCHA was required before you could authenticate; however, I was able to bypass the CAPTCHA by removing it from the request.
After doing some testing and investigating the CAPTCHA portal, we discovered that the front-end code for the CAPTCHA had been implemented, but the back-end code had not. This is a failure of security in the code.
If anyone on the application security team had logged into the CAPTCHA portal, they would have immediately noticed that challenges were being issued, but not validated. This is a failure of security outside the code.
The dev team incorrectly assumed that users had to use the front-end application to send authentication requests. This is a failure around the code. Hopefully you’re starting to see the pattern. Most compromises will have failures at every layer, or maybe even between layers.
After ensuring the CAPTCHA was implemented correctly, we saw a major reduction in the scale and success rate of credential stuffing attacks. There were more bugs to follow: WAF bypasses, another CAPTCHA bypass, and smarter attacks with new tricks, but we stopped the attack by identifying and fixing issues across the entire application security stack.
The purpose of telling this story was neither to debase the teams that work on this app nor to take a personal victory lap. I want you to see a very real scenario where every existing control failed, process failed, and tunnel vision prevented the very talented professionals working the issue from seeing what was happening. If we silo our thinking and relinquish responsibility for the unfamiliar, we’re imposing an artificial handicap on ourselves that will lose us the game.
Application security does not belong to a single person, team, or even department. It is easy to silo your thinking and focus on a small number of things that contribute to a successful application security program, but someone has to see the big picture.
Application security programs tend to fail in the gaps between layers. The most successful application security programs spend a lot of time figuring out how security controls interact, overlap, and compensate for deficiencies in other controls. If your goal in reading this is to improve the security of an application you are responsible for, join me in the next post where I walk through how I map application attack surfaces.