Lists & Roundups

10 Web Application Security Mistakes Found in Code Reviews

The ten findings that come up again and again when we review web applications, from missing ownership checks to unread logs. For each one: what it looks like, why it is a risk and the fix.

10 Web Application Security Mistakes Found in Code Reviews

When we review an application before taking it over, the findings repeat, whatever the language or framework. Few involve clever attacks. Most are ordinary shortcuts taken under deadline that nobody came back to. These are the ten web application security mistakes we see most often, grouped by where they live in the code.

Each one maps to a category in the OWASP Top 10, the reference most security reviews are measured against. Every item says what it looks like, why it is a risk and what the fix is.

Who is allowed to do what

1. Permission checks that exist only in the interface

What it looks like: the Delete button is hidden for ordinary users, but the address behind it works for anyone who is logged in. A record is loaded by the ID in the URL with no condition on who owns it, so /invoices/1042 shows invoice 1042 to every customer.

Why it is a risk: anyone with an account can read or change other customers' data by editing a number. Broken access control is the first category on the OWASP list.

The fix: check permission on the server for every request, and include the owner or tenant in every query for a record. Keep the rules in one place and test with two accounts from different customers.

2. Admin tools protected by an address nobody is supposed to know

What it looks like: an admin area at an unusual path with a weak login or none, a leftover debug route, a database tool in a subfolder, an export script, or a staging site that holds a copy of production data.

Why it is a risk: automated scanners try common paths all day, and addresses leak through logs and browser history. Obscurity only delays discovery.

The fix: every internal tool requires login and a role. Restrict admin tools to a VPN or known IP addresses, remove debug endpoints from production, and keep staging behind authentication with masked data.

3. Sessions and tokens that never end

What it looks like: logout deletes the cookie in the browser while the session stays valid on the server. Password reset links work for days and more than once. API tokens cannot be revoked, and nothing limits login attempts.

Why it is a risk: a token stolen once keeps working, and passwords leaked from other sites can be tried against your login without limit.

The fix: end sessions on the server, issue a new session ID at login, and close other sessions when a password changes. Make reset links expire quickly and work once. Rate limit login and reset, and require a second factor for admin accounts.

What the application does with input

4. SQL assembled from strings

What it looks like: most queries use parameters, and then there are the exceptions: a search filter, a sort column taken from the request, an IN (...) list built with a join, or a raw fragment passed into an ORM helper such as whereRaw().

Why it is a risk: one injectable query can expose or alter the whole database, not only the table behind that page.

The fix: bind every value as a parameter. Column names and sort directions cannot be bound, so compare them against a fixed list. Search the code for every raw SQL call and review each one.

5. Trusting what the browser sends

What it looks like: validation exists only in JavaScript. A price, discount, role or user ID arrives in a hidden field or a JSON body and is used as sent. A model is filled from the entire request, so an extra is_admin field is saved along with the name and email.

Why it is a risk: any request can be edited with the browser's developer tools. Users can set their own price or promote themselves.

The fix: validate on the server, always. Calculate prices, totals and ownership there. Write only an explicit list of fields, using $fillable in Laravel, $allowedFields in CodeIgniter 4 or the equivalent in your stack.

6. Output printed without escaping

What it looks like: a template uses the raw-output syntax because the escaped one "broke the formatting". JavaScript writes API data into the page with innerHTML. A plain echo prints a value from the database.

Why it is a risk: text entered by one user runs as script in another user's browser. The worst case is the admin panel, where a comment or a company name submitted by a customer executes with an administrator's session.

The fix: use the template engine's default escaping everywhere, and make every exception justify itself. Clean rich text with a maintained sanitizer and an allow-list of tags. A Content Security Policy and HttpOnly cookies add a second layer.

Configuration and secrets

7. Secrets in the repository and in the front end

What it looks like: a .env file or a config file with live database credentials is committed. Private API keys sit in a JavaScript bundle or a mobile app. Staging and production share the same passwords.

Why it is a risk: everyone who can read the repository, former contractors included, can reach production. Deleting the file later does not help, because the history keeps it.

The fix: keep secrets in environment variables or a secrets manager. Rotate every credential that was ever committed. Give each environment its own credentials, and ship only publishable keys to the browser.

8. Debug mode and detailed errors in production

What it looks like: APP_DEBUG=true, display_errors=On or a development environment setting on the live server. Stack traces show queries and file paths. An exception handler catches a failed permission or payment check and carries on as if it had passed.

Why it is a risk: error pages hand an attacker a map of the system and sometimes credentials. Code that continues after a failed check turns an outage at a third party into a bypass.

The fix: make production settings part of the deployment and verify them after each release. Show generic error pages and log the detail. When a check cannot complete, refuse the action.

Keeping it safe after launch

9. Dependencies nobody updates

What it looks like: a lock file untouched for years, abandoned packages, a framework past its end of support, scripts loaded from third-party servers without a pinned version.

Why it is a risk: vulnerabilities in popular packages are public and scanned for automatically. The current OWASP list has software supply chain failures as a category of its own.

The fix: run composer audit, npm audit or your stack's equivalent in the build. Update monthly, remove packages you no longer use, and keep the language runtime and the framework on supported versions.

10. No logs worth reading, and nobody reading them

What it looks like: failed logins, refused permissions, admin actions and data exports leave no trace. Or the reverse: logs contain passwords and tokens. Nothing raises an alert, and logs are stored only on the server they describe.

Why it is a risk: an intrusion goes unnoticed, and afterwards nobody can say what was accessed. That makes any duty to notify customers harder to meet. What that duty is depends on your jurisdiction, so confirm it with your own counsel.

The fix: record security events with who, what, when and from where. Keep secrets out of logs, send them to a separate system, alert on spikes in failures, and make one person responsible for a weekly look.

Checking your own code for these web application security mistakes

Start with items 1, 4 and 5. They are the most common and the most damaging, and a developer who knows the code can test them with two user accounts and the browser's network tab. Items 7 to 9 are quick to verify and usually quick to fix, and a committed secret should be rotated the day you find it. Items 3 and 10 take longer because they need design decisions.

For detail on a single topic, the OWASP Cheat Sheet Series is a free reference, and the Application Security Verification Standard turns the same ground into requirements you can put in a specification. PHP teams will find a language-specific version in our PHP application security checklist, and API builders in API security best practices.

An outside review is worth paying for when the application holds payment or personal data, when a customer asks for evidence, or when the team that wrote the code is the only one that has ever read it. In our web application development projects, requirements like these go into the specification, and we test to OWASP guidance where the client asks for it. For systems that are already live, the same checks are part of taking an application into maintenance and support.

Frequently asked questions

Does using a framework prevent these mistakes?

It prevents some by default: query binding, output escaping and CSRF protection are built into Laravel, CodeIgniter and their peers. It does not write your permission rules, manage your secrets or update itself. Most findings in framework-based applications sit where the defaults were bypassed.

Can an automated scanner find all of this?

No. Scanners are good at outdated packages, missing headers and some injection flaws. They cannot know that customer A should not see customer B's invoice, which is the most serious class of problem. Use scanners for breadth and a human review for access control and business logic.

Do small applications get attacked?

Yes, because most attacks are automated and do not choose targets by size. Scripts look for known weaknesses across every address they can reach, and a small application with an old package or an open admin tool is found the same way a large one is.

Add WorldWin Coder to your preferred sources

Add worldwincoder.com as a preferred source on Google, or open this article in your AI assistant to use it as a source.

Swati Priyadrshni
· Founder & CEO at WorldWin Coder

I'm Swati Priyadarshani, Founder & CEO of LMS Advisor and Co-Founder of WorldWin Coder Pvt. Ltd. (est. 2019). Over the last 10+ years, I've helped enterprises build learning platforms that actually get used - not just deployed.

Keep reading

Have something to build, fix or move?

Tell us where you are. A developer reads every inquiry, and you get next steps and a free quote within one business day.