Principle of Least Privilege
debt(d8/e6/b6/t6)
Closest to 'silent in production until users hit it' (d9), slightly better at d8 because semgrep can flag some patterns (root processes, GRANT ALL) but most over-privilege is invisible until a breach. detection_hints.automated is 'no'.
Closest to 'cross-cutting refactor across the codebase' (e7), slightly easier at e6 because while quick_fix sounds simple ('give minimum permissions'), in practice tightening DB grants, process users, API key scopes, and service accounts spans infrastructure, deployment, and code — not a one-line fix.
Closest to 'strong gravitational pull' (b7), slightly less at b6 because applies_to spans web/api/cli/queue-worker contexts and shapes how every component is provisioned and deployed, but it's an enabling discipline rather than a single load-bearing abstraction.
Closest to 'serious trap' (t7), slightly less at t6 because the misconception (that PoLP only applies to user accounts/DB permissions) leads developers to miss API tokens, service accounts, process users, and extension scope — a broad blind spot but not behavior-contradicting.
Also Known As
TL;DR
Explanation
PoLP limits the blast radius of a compromise. A database user that can only SELECT and INSERT cannot DROP tables if SQL injection occurs. A PHP process that can only write to /var/www/uploads cannot overwrite system files if file upload validation fails. Apply PoLP at every layer: database users, OS file permissions, API token scopes, and PHP function allow-lists. Regularly audit what permissions are actually needed vs. what is granted.
Common Misconception
Why It Matters
Common Mistakes
- Database users with GRANT ALL instead of SELECT, INSERT, UPDATE on specific tables.
- Application running as root or with sudo — a compromise gives attacker full system access.
- API keys with write permissions for services that only need read access.
- Developers with production database write access they never use — privileged access should be time-bounded.
Code Examples
// DB user with excessive privileges:
$pdo = new PDO('mysql:host=db', 'root', 'password'); // Root user in app!
// Compromise = attacker can DROP DATABASE, create admin users, read all data
// Least privilege:
$pdo = new PDO('mysql:host=db', 'app_user', $pass);
// app_user: SELECT, INSERT, UPDATE on app_db.* only — no DROP, no GRANT
-- DB user for the web app — only needs SELECT/INSERT/UPDATE/DELETE on app tables
-- Never run the app as root or with GRANT OPTION
CREATE USER 'webapp'@'%' IDENTIFIED BY '...secure...password...';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'webapp'@'%';
-- Separate user for migrations (can ALTER, CREATE, DROP):
CREATE USER 'migrator'@'localhost' IDENTIFIED BY '...';
GRANT ALL PRIVILEGES ON myapp.* TO 'migrator'@'localhost';
-- PHP — never store secrets with broader permissions than needed
-- File permissions: config files 640, not 777
-- PHP-FPM process user: www-data, not root
-- open_basedir restricts PHP to its own directory tree