# Security Code Review for PHP Projects

> Security code review for PHP: baseline or diff, risky functions, tools such as PHPStan and Psalm, and a checklist for your own team.

Source: https://phpsos.de/en/blog/sicherheits-code-review-php/  
As of: 25/10/2026  
Provider: PHP SOS, PHP emergency help and server security. Immediate help via WhatsApp: https://wa.me/491736494914?text=Hello%20PHP%20SOS%2C%20we%20need%20help%20with%20our%20PHP%20server.%20Company%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**In short:** A security code review for PHP is the targeted reading of source code with one question: where can foreign input do something it is not allowed to? Two forms have proven themselves, a review of every change and a baseline review of the whole project, supported by static analysis with PHPStan or Psalm. A review does not find vulnerabilities in the PHP interpreter such as PHP2Shell, but it does find the many errors that arise in your own code.

## Why Look at Your Own Code Right Now?

In the last week of October 2026, PHP2Shell kept mainly admins busy. Patch, restart, prove: the work lay on the server. For development teams, an uncomfortable question remains afterwards. If an attacker can execute code through another vulnerability, what does he find in our application? And how many of these vulnerabilities did we write ourselves?

The OWASP Top 10 have shown for years that most vulnerabilities in web applications are not exotic. Missing access control, injection and insecure configuration rank high. These are errors that a practiced eye finds in the source code long before an attacker tries them out.

There is also a practical reason. Many companies are having their servers reviewed, patched and hardened right now anyway. Anyone who looks at their own application in the same go closes the gap between operations and development. A hardened server with a vulnerable application remains attackable, and so does a cleanly written application on unpatched PHP.

## Baseline Review or Change Review?

The OWASP cheat sheet on secure code review distinguishes two types that complement each other in practice:

| Type | When | Scope | Goal |
|---|---|---|---|
| Baseline review | new project, major release, after an incident | whole project, weighted by risk | record the stock of vulnerabilities |
| Change review (diff) | every pull request | changed code only | prevent new errors |

A baseline review after an incident is especially valuable. Anyone who has just cleaned up a server should know whether the application offers further points of entry. The change review keeps the state clean afterwards, because every change is also read from a security perspective before it is merged.

## Code Review in PHP: Where Security Errors Accumulate

In PHP projects, a targeted look at certain functions and patterns is worthwhile. They are not forbidden, but every match deserves the question of whether foreign data can get in.

| Pattern in the code | Possible risk | Further reading |
|---|---|---|
| SQL via string concatenation with variables | SQL injection | [Preventing SQL Injection in PHP](https://phpsos.de/en/ratgeber/sql-injection-php/) |
| `unserialize()` on data from outside | object injection | [Insecure Deserialization in PHP](https://phpsos.de/en/ratgeber/deserialisierung-php/) |
| `include` or `require` with a variable path | inclusion of foreign files | [Preventing Local and Remote File Inclusion](https://phpsos.de/en/ratgeber/lfi-rfi/) |
| `exec()`, `system()`, `shell_exec()`, `proc_open()` | command execution | command injection |
| Output without `htmlspecialchars()` | cross-site scripting | context-appropriate escaping |
| `==` with tokens or hashes | type conversion bypasses checks | `hash_equals()`, strict comparisons |
| `eval()`, `extract()` on input | code or variable injection | usually delete without replacement |

A quick first overview is possible with a simple search. It does not replace a review but shows where to begin:

```bash
# Matches of risky functions in your own code (vendor excluded)
grep -rnE "\b(unserialize|eval|extract|shell_exec|exec|system|passthru|proc_open)\s*\(" src/ app/ 2>/dev/null
```

At least as important is what is missing in the code. Does every controller check whether the logged-in user may view or change exactly this record? Are uploads restricted by type and storage location? No search for function names finds such gaps, only reading the flow.

## Tools That Support the Review

Static analysis checks code without executing it. PHPStan and Psalm find type errors, unreachable code and wrong assumptions about return values. Psalm additionally offers a taint analysis that tracks whether data from requests flows unchecked to critical places. Both can be tightened step by step so that older projects can get started too. An overview is given in [Static Analysis: PHPStan and Psalm](https://phpsos.de/en/php/statische-analyse/).

```bash
# Static analysis in the project, raise the level step by step
vendor/bin/phpstan analyse src --level=5
# Taint analysis with Psalm
vendor/bin/psalm --taint-analysis
```

Tools deliver hints, not verdicts. Every match needs an assessment, and an empty report does not mean the application is secure.

Just as important as finding is recording. Every finding should be captured with location, a short description, a risk assessment, recommended remediation and status, ideally directly in the team's ticket system. That makes it possible to trace what was fixed, what was deliberately accepted and what is still open. After the fix, a second look is worthwhile: has the cause been eliminated or only the one symptom? Does the same pattern appear in other places in the code? In experience, a mistake that was made once is rarely found in only one place.

## A Checklist for Your Own Team

For change reviews, a short, fixed list has proven itself. It belongs in the template for pull requests:

1. Where does all the data this change processes come from, and is it validated on the server side?
2. Are database queries built exclusively with placeholders?
3. Is every output escaped for its context, that is, HTML, attribute, JavaScript or URL?
4. Does the code check authorization for exactly this object, not just the login?
5. Do passwords, tokens or personal data end up in logs or error messages?
6. Are secrets in the code or in versioned files?
7. Were new dependencies added, and are they maintained?

> **Tip:**
> Always have security-critical parts such as login, rights management, payment flows and uploads read by a second person who was not involved in the code. A fresh pair of eyes finds assumptions that the author considers self-evident.

## How does PHP SOS help?

- Together with specialized partners, we carry out a baseline review of your PHP application, weighted toward the parts with the highest risk.
- We set up PHPStan or Psalm to match the state of your project and write the checklist for your pull requests.
- We combine the review with a look at server and configuration, because many vulnerabilities arise only in the interplay.
- Where a review from outside is desired, we supplement the review with a [security audit and penetration test](https://phpsos.de/en/leistungen/sicherheitsaudit-penetrationstest/).

**Conclusion:** A code review is the cheapest place to fix security errors, namely before they are shipped. Anyone who checks every change with a short list and occasionally goes through the project completely reduces the attack surface permanently.


## Frequently asked questions

**What is the difference between a code review and a penetration test?**  
A code review reads the source code and finds errors before they are shipped. A penetration test attacks the running application from outside. The two complement each other: the review finds causes, the test shows what is actually exploitable.

**Does a code review find vulnerabilities like PHP2Shell?**  
No. PHP2Shell sits in the PHP interpreter, not in the application code. Only a PHP update with a restart helps against it. A review finds errors in your own code, such as injection, missing authorization checks or insecure deserialization.

**Are PHPStan or Psalm enough for a security review?**  
They are a good foundation and find many errors automatically. Logic errors, missing authorization checks and wrong assumptions about workflows, however, can only be recognized by a person who knows what the application is supposed to do.

**How long does a security code review take?**  
That depends on the scope. A review of every change in the pull request takes little time. A complete review of a grown project is a project of its own, which you limit by risk to the most important parts.

## Sources

- [OWASP: Secure Code Review Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secure_Code_Review_Cheat_Sheet.html)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [PHPStan](https://phpstan.org/)
