Case Study:

SIGIL Infrastructure hardening manifest engine for LEMP

Project Overview

Sigil is an open-source PHP CLI tool for auditing and hardening self-hosted LEMP stacks. It scans your actual server configuration files — .env, nginx.conf, docker-compose.yml, php.ini, and database configs — against a library of 49 security rules, scores findings by severity, generates executable patches, and tracks configuration drift between deploys.

It is designed for developers and backend engineers who manage their own servers and need a structured, repeatable way to catch misconfigurations before they become incidents. Think of it as composer audit for your entire infrastructure stack — not just your dependencies.

The Problem

Self-hosted stacks have no built-in security feedback loop. When a developer deploys a Laravel app on a VPS with Docker and Nginx, there is no tool that tells them their APP_DEBUG is still true in production, their .env file is publicly reachable through Nginx, their PHP-FPM container is running as root, or their database port is bound to 0.0.0.0 on the host.

These are not rare edge cases — they are the default state of a freshly deployed stack. Developers fix them manually, inconsistently, and only after something goes wrong. Sigil makes that feedback loop explicit, automatic, and repeatable.

How It Works

Sigil follows a strict three-layer architecture: Parse → Evaluate → Report. No layer bleeds into another.

  • Parsers — read configuration files (.env, nginx.conf, docker-compose.yml, php.ini, my.cnf, pg_hba.conf) into a ScanContext data container. Rules never read files directly.
  • Rules — read-only. Each rule interrogates the ScanContext and returns a FindingCollection. Rules never touch the filesystem.
  • Fixers — the only layer that writes files. Always creates a timestamped backup under .sigil/backups/ before modifying anything.
  • Reporters — render findings to CLI (colored output), JSON (for CI/CD pipelines), or unified diff patch files.

Stack detection is automatic. Sigil reads your .env, docker-compose.yml, and filesystem to detect your framework, web server, and database engine — no configuration flags required in most cases.

Commands

Sigil ships five commands, each with a distinct responsibility:

Command Purpose
sigil scan [path]Audit the stack against all 49 rules. Outputs CLI report, JSON, or patch files.
sigil enforce [--dry-run] [--rule=ID]Apply auto-fixes for eligible findings. Always backs up before writing. Supports dry-run preview.
sigil snapshot [path]Save the current configuration as an HMAC-signed baseline for drift comparison.
sigil drift [path]Compare current configuration against the last snapshot. Flags any changed values.
sigil rules [--category=]List all available rules with severity levels and descriptions.

The scan command output scores the project out of 100 and groups findings by layer — Laravel/PHP, Nginx, Docker, and the detected database engine — so developers know exactly where to focus remediation effort.

Rule Library

49 rules across six categories, each mapped to a severity level and a remediation mode. Database rule packs are loaded automatically based on the detected engine.

Category Rules Example Findings
Laravel / PHPL001–L012APP_DEBUG=true in production, APP_KEY not set, CSRF middleware removed, world-writable storage/, dangerous PHP functions exposed
NginxN001–N011.env publicly accessible, missing HSTS/CSP/X-Frame-Options headers, directory listing enabled, weak TLS protocols, no rate limiting on auth routes
DockerD001–D009Container running as root, Docker socket mounted, privileged: true, database port bound to 0.0.0.0, secrets in plain environment variables
MySQLM001–M005App connecting as root, port 3306 exposed to host, no SSL for DB connections, known-insecure version
MariaDBMB001–MB005Root DB user, missing STRICT_TRANS_TABLES, port exposure, no SSL — with unix_socket auth correctly treated as a PASS
PostgreSQLPG001–PG007Superuser as app user, trust auth in pg_hba.conf, ssl=off, unrestricted host access, missing audit logging

Severity & Remediation Model

Sigil never applies destructive fixes silently. Remediation is tiered by severity so that high-risk changes always stay under developer control.

Severity Meaning Remediation Mode
CRITICALActive exploitation vector — requires immediate actionManual remediation guide with exact commands and file references
HIGHSignificant exposure with likely exploitabilityManual remediation guide
MEDIUMExploitable under specific conditionssigil scan --output=patch — generates a reviewable unified diff for you to apply
LOWBest-practice deviation with low immediate risksigil enforce — auto-applied after backup, with dry-run preview available
INFOInformational, not a vulnerabilityAuto-applied

Before any file is modified, Sigil writes a timestamped backup to .sigil/backups/. CRITICAL and HIGH findings are never auto-applied under any circumstance — Sigil outputs precise, actionable instructions with file line references instead.

Drift Detection

Beyond one-time auditing, Sigil supports ongoing configuration integrity tracking through snapshot and drift commands. After a deploy or a round of fixes, sigil snapshot saves the current configuration state as an HMAC-signed baseline stored in .sigil/snapshots/.

Running sigil drift at any point afterward compares the live configuration against that baseline and flags every value that changed — new environment variables, modified php.ini directives, changed Nginx blocks, or removed rules. This makes it practical to detect accidental regressions, unauthorized changes, or configuration drift introduced during a deploy without re-running a full audit from scratch.

Tech Stack

Layer Technology
LanguagePHP 8.3
CLI FrameworkSymfony Console 7
Config ParsingSymfony YAML, custom parsers for Nginx / php.ini / pg_hba.conf
File OperationsSymfony Filesystem, Symfony Process
CVE DataNIST NVD API v2 with 24-hour local cache
Snapshot IntegrityHMAC-SHA256 signatures
DistributionComposer global install (jcadima/sigil on Packagist)
TestingPHPUnit 11 with fixture-based integration tests

Sigil has no framework dependency — it uses four standalone Symfony components and runs on any Linux server with PHP in $PATH. Install is a single Composer command; no daemon, no agent, no persistent process.

Outcome

Sigil gives solo developers and small engineering teams a structured security baseline for self-hosted stacks without requiring a DevSecOps background or expensive tooling. A single sigil scan surfaces misconfiguration across all layers of the stack in seconds, with severity-ranked findings, exact file references, and actionable remediation for every rule that fires.

The tool is available on Packagist at jcadima/sigil and installs globally in one command. After installation, any developer can audit a Laravel project on a self-hosted LEMP stack, apply safe fixes immediately, and track configuration integrity across future deploys — without leaving the terminal.