← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Input Validation vs Output Encoding

General PHP 5.0+ Beginner
debt(d7/e5/b7/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints specify phpstan, psalm, and semgrep with automated=no. These specialist tools can flag unvalidated input in some patterns, but the code_pattern note shows it requires recognising absence of validation — something these tools cannot reliably catch automatically, pushing it toward d7 rather than d5. Missing validation is typically found via manual code review or when attacks succeed in production.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes validating type, format, length, and range at entry points across web, api, and cli contexts. Retrofitting server-side validation across all entry points — user input, API payloads, file uploads, query strings — touches multiple controllers, request handlers, and possibly a shared validation layer. This is more than a single-line fix but less than a full architectural rework.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7). The applies_to covers web, api, and cli contexts from PHP 5.0 onward, meaning every external data entry point in the system must account for this choice. The common_mistakes include second-order attacks (stored data reused without re-validation), meaning validation decisions at ingestion shape how data is trusted throughout the entire codebase. Every new feature accepting external input must be written with this discipline in mind.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The misconception field directly states the canonical wrong belief: 'Client-side validation is sufficient if it covers all cases.' This is a well-documented but persistently harmful mistake — developers coming from frontend contexts naturally conflate UX validation with security validation. The common_mistakes reinforce this: trusting client-side JavaScript, validating format but not range, and blocklisting instead of allowlisting are all intuitive-seeming but wrong approaches that a competent developer can easily fall into.

About DEBT scoring →

Also Known As

data validation input sanitisation server-side validation

TL;DR

Validation checks that input is acceptable; output encoding makes data safe for the context it's rendered in. Both are required.

Explanation

Input validation and output encoding are complementary — not alternatives. Validation (reject unexpected characters, enforce length and format) reduces the attack surface and catches mistakes early. Output encoding (htmlspecialchars for HTML, parameterised queries for SQL, json_encode for JS) makes data structurally safe for its destination context. Relying on validation alone fails because valid-looking data can still be malicious in a different context. Encode for the output context regardless of how the input was validated.

Common Misconception

Client-side validation is sufficient if it covers all cases. Client-side validation is UX — it can be bypassed by disabling JavaScript or crafting raw HTTP requests. Server-side validation is the security control; client-side is purely for user experience.

Why It Matters

Unvalidated input is the root cause of injection attacks, unexpected behaviour, and data corruption. Validating on the server side — not just the client — ensures your application only processes data it was designed to handle.

Common Mistakes

  • Relying on client-side (JavaScript) validation alone — it is trivially bypassed with browser dev tools.
  • Validating format but not range — accepting a birth year of 9999 is a validation failure.
  • Blocklisting known bad input instead of allowlisting known good — attackers always find new bypass strings.
  • Validating on the way in but re-using stored data later without re-validation (second-order attacks).

Avoid When

  • Validating only on the client side — client-side validation is for UX; server-side validation is for security.
  • Using validation as a substitute for parameterised queries — validate AND use prepared statements.
  • Allowlist validation that is too permissive — a regex that allows < and > defeats XSS protection.
  • Validating after business logic has already acted on the input — validate at the entry point, before any processing.

When To Use

  • Every piece of data entering the system from an external source — user input, API payloads, file uploads, query strings.
  • Allowlist validation (accept only known-good patterns) rather than blocklist (reject known-bad).
  • Before passing data to any downstream system — database, shell command, template engine, serialiser.
  • Structured data like emails, URLs, dates — use format-specific validators, not generic string checks.

Code Examples

✗ Vulnerable
// Sanitising instead of validating — trying to fix bad input rather than reject it
$email = strip_tags($_POST['email']);
$age   = (int) $_POST['age']; // -1 passes silently
✓ Fixed
// Validate — reject anything that doesn't match expectations
$email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL)
    ?: throw new \InvalidArgumentException('Invalid email');

$age = filter_var($_POST['age'] ?? '', FILTER_VALIDATE_INT,
    ['options' => ['min_range' => 0, 'max_range' => 150]])
    ?: throw new \InvalidArgumentException('Invalid age');

// In Laravel — Form Request
class StoreUserRequest extends FormRequest {
    public function rules(): array {
        return [
            'email' => ['required', 'email:rfc,dns', 'max:255', 'unique:users'],
            'age'   => ['required', 'integer', 'between:0,150'],
            'role'  => ['required', Rule::in(['user', 'editor'])],
        ];
    }
}

Added 13 Mar 2026
Edited 25 Mar 2026
Views 132
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 1 ping M 2 pings T 6 pings W 5 pings T 14 pings F 8 pings S 19 pings S 11 pings M 0 pings T 0 pings W 2 pings T 2 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 1 ping S 2 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Scrapy 63 Perplexity 12 Amazonbot 10 SEMrush 6 Ahrefs 5 ChatGPT 4 Google 3 Unknown AI 3 Bing 3 Claude 2 PetalBot 2 Majestic 1 Qwen 1 Common Crawl 1
crawler 112 crawler_json 3 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Validate type, format, length, and range at the entry point; use allowlists not blocklists; reject invalid input early with a 400 response
📦 Applies To
PHP 5.0+ web api cli
🔗 Prerequisites
🔍 Detection Hints
User input used in business logic without type cast, filter_var, or validation before use
Auto-detectable: ✗ No phpstan psalm semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update
CWE-20 CWE-807


✓ schema.org compliant