# PHP Vulnerability Examples and Fixes

> **Use this page when:** reviewing PHP services, old MVC applications, upload paths, or utility endpoints that mix user input with shell, filesystem, or SQL operations.

## How to read these examples

* **Vulnerable snippet** shows the unsafe habit.
* **Safer pattern** shows the direction you want in production code.
* **Why it matters** ties the defect to attacker value and business impact.
* **Review cue** is phrased so it can become a pull-request comment or checklist item.

## Example 1 — SQL injection through string concatenation

### Vulnerable snippet

```php
$email = $_GET['email'];
$sql = "SELECT id, role FROM users WHERE email = '$email'";
$result = $pdo->query($sql);
$user = $result->fetch();
```

### Safer pattern

```php
$stmt = $pdo->prepare("SELECT id, role FROM users WHERE email = :email");
$stmt->execute(['email' => $_GET['email']]);
$user = $stmt->fetch();
```

**Why it matters**

* String-built queries let attacker-controlled input change the meaning of the SQL statement.

**Business impact**

* Account enumeration, full data exposure, privilege escalation, or destructive queries against production data.

**Review cue**

* Do not concatenate request data into SQL. Require prepared statements or a safe query builder for all value binding.

## Example 2 — Reflected or stored XSS in output rendering

### Vulnerable snippet

```php
$comment = $_POST['comment'];
echo "<div class='comment'>$comment</div>";
```

### Safer pattern

```php
$comment = $_POST['comment'] ?? '';
echo "<div class='comment'>" . htmlspecialchars($comment, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . "</div>";
```

**Why it matters**

* Raw HTML output turns user-controlled content into executable script in the victim browser.

**Business impact**

* Session theft, account takeover, admin-action forgery, phishing overlays, and supply-chain-like browser compromise.

**Review cue**

* For every rendering context, demand context-appropriate output encoding or safe templating helpers instead of raw echo.

## Example 3 — Unsafe file upload that trusts file name and extension

### Vulnerable snippet

```php
$name = $_FILES['file']['name'];
move_uploaded_file($_FILES['file']['tmp_name'], __DIR__ . '/public/uploads/' . $name);
echo 'uploaded';
```

### Safer pattern

```php
$allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png'];
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['file']['tmp_name']);

if (!isset($allowed[$mime])) {
    http_response_code(400);
    exit('unsupported file type');
}

$random = bin2hex(random_bytes(16)) . '.' . $allowed[$mime];
$target = '/srv/app-uploads/' . $random; // outside web root
move_uploaded_file($_FILES['file']['tmp_name'], $target);
```

**Why it matters**

* Original names, fake extensions, and web-root storage allow web shells, polyglots, overwrite attacks, and unsafe direct retrieval.

**Business impact**

* Remote code execution, malware distribution, storage abuse, or public leakage of sensitive files.

**Review cue**

* Require type allowlists, generated names, size limits, storage outside web root, and separate retrieval controls.

## Example 4 — Broken object-level authorization (IDOR)

### Vulnerable snippet

```php
$invoiceId = (int) $_GET['invoice_id'];
$stmt = $pdo->prepare("SELECT * FROM invoices WHERE id = :id");
$stmt->execute(['id' => $invoiceId]);
$invoice = $stmt->fetch();
```

### Safer pattern

```php
$invoiceId = (int) $_GET['invoice_id'];
$userId = $_SESSION['user_id'];

$stmt = $pdo->prepare(
    "SELECT * FROM invoices WHERE id = :id AND owner_user_id = :user_id"
);
$stmt->execute(['id' => $invoiceId, 'user_id' => $userId]);
$invoice = $stmt->fetch();

if (!$invoice) {
    http_response_code(404);
    exit('not found');
}
```

**Why it matters**

* Looking up objects by ID without ownership or role scope means any authenticated user can pivot into another user’s records.

**Business impact**

* Cross-tenant data disclosure, unauthorized financial actions, privacy incidents, and support/admin trust breakdown.

**Review cue**

* Every record fetch for sensitive data should prove scope: owner, tenant, team, or explicit delegated permission.

## Example 5 — Command injection through shell\_exec

### Vulnerable snippet

```php
$term = $_GET['term'];
$output = shell_exec("grep -R $term /srv/docs");
echo nl2br($output);
```

### Safer pattern

```php
$term = $_GET['term'] ?? '';
if (!preg_match('/^[a-zA-Z0-9._ -]{1,40}$/', $term)) {
    http_response_code(400);
    exit('bad search term');
}

$matches = [];
foreach (glob('/srv/docs/*.txt') as $file) {
    foreach (file($file, FILE_IGNORE_NEW_LINES) as $line) {
        if (str_contains($line, $term)) {
            $matches[] = $line;
        }
    }
}

echo nl2br(htmlspecialchars(implode("
", $matches), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'));
```

**Why it matters**

* Shell interpolation makes metacharacters part of the command, not just part of the search term.

**Business impact**

* Remote code execution, data exfiltration, lateral movement, and compromise of the host or its secrets.

**Review cue**

* If user input reaches a shell, stop. Prefer native language functions, strict validation, and no shell expansion.

## Related pages

* [Backend Service Security Guides by Stack](/application-security-and-secure-sdlc/index-4/backend-service-security-guides-by-stack.md)
* [Web Application Security Review and Architecture Playbook](/application-security-and-secure-sdlc/index-1/web-application-security-review-and-architecture-playbook.md)
* [Repository Secret Scanning](/application-security-and-secure-sdlc/index-1/repository-secret-scanning.md)

***

*Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.product-security.expert/application-security-and-secure-sdlc/index-4/php-vulnerability-examples-and-fixes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
