Skip to main content

Web server configuration security audit tool

Project description

webconf-audit

CI PyPI Python versions License: MIT

A security auditing tool for web server configurations.

webconf-audit has two independent analysis modes:

  • Local — static analysis of configuration files on the host that runs the web server.
  • External — black-box probing of a running web endpoint over the network using observable HTTP, HTTPS, and TLS signals.

Supported servers

Local analysis covers four web servers:

  • Nginx
  • Apache HTTP Server
  • Lighttpd
  • Microsoft IIS

External probing is server-agnostic; a few checks are activated only after fingerprinting identifies the underlying server (for example, Apache mod_status exposure or IIS detailed error pages).

Installation

webconf-audit requires Python 3.10 or later.

pip install webconf-audit

For reproducible CI usage, pin the published release:

pip install webconf-audit==0.1.4

The package exposes a webconf-audit console entry point. Every command is also available via python -m webconf_audit.cli.

Project links:

Quick start

Local analysis

webconf-audit analyze-nginx /etc/nginx/nginx.conf
webconf-audit analyze-apache /etc/apache2/httpd.conf
webconf-audit analyze-lighttpd /etc/lighttpd/lighttpd.conf
webconf-audit analyze-iis C:\inetpub\wwwroot\web.config
webconf-audit analyze-iis C:\inetpub\wwwroot\web.config --tls-registry schannel.json

External analysis

webconf-audit analyze-external https://example.com
webconf-audit analyze-external example.com --ports 80,443,8443
webconf-audit analyze-external example.com --no-scan-ports

Output formats

Every analyze-* command supports text (default) and JSON output:

webconf-audit analyze-nginx config.conf --format json
webconf-audit analyze-external example.com -f json
webconf-audit analyze-nginx config.conf --group-by standard
webconf-audit analyze-nginx config.conf --group-repeated

The JSON envelope contains a generation timestamp, a summary, the per-target results, the deduplicated findings list, repeated finding groups under finding_groups, standards references under each finding and the top-level standards summary, and the issues list. Schema version 1 also adds top-level schema_version and generator fields so downstream tooling can verify the report format, generator package name and version, and registry revision. See docs/report-format.md for the full JSON contract.

When an explicit policy is supplied, JSON results also include additive result.metadata.audit_policy and result.metadata.rule_execution entries. See docs/audit-policy.md and docs/report-format.md.

Use --group-repeated with text output to collapse repeated findings that share the same rule, severity, recommendation, and report grouping cause while preserving each exact source location.

Use --group-by standard with text output to review findings by mapped standards such as CWE, OWASP Top 10, and OWASP ASVS. Findings with no mapped standard are grouped under Unmapped.

CI gating

Every analyze-* command can act as a CI gate with --fail-on:

webconf-audit analyze-nginx nginx.conf --fail-on medium
webconf-audit analyze-external example.com --fail-on high --format json

Exit codes in CI-gating mode:

  • 0 - analysis completed and no findings at or above the selected severity were found.
  • 1 - analysis produced an execution or configuration error.
  • 2 - analysis completed and at least one finding met the selected severity threshold.

JSON findings include a stable fingerprint field that is designed for CI, suppressions, and baseline/diff reporting.

When --fail-on is used, .webconf-audit-ignore.yml is read from the current working directory if it exists. Suppressions require rule_id, either a fingerprint or locator fields, a human-readable reason, and an expires date. Expired suppressions stop hiding findings and are reported as analysis issues.

suppressions:
  - rule_id: nginx.server_tokens_on
    source: nginx.conf
    line: 12
    reason: Accepted for staging until the shared image is rebuilt.
    expires: 2026-12-31

Use --suppressions <path> to point at a non-default suppression file. Full CI examples are available in docs/ci-integration.md.

Baseline and diff mode

Use --write-baseline to capture the current accepted finding set:

webconf-audit analyze-nginx nginx.conf --write-baseline webconf-audit-baseline.json

Use --baseline to compare a later run against that known state. Text output shows a short diff summary, and JSON output includes new_findings, unchanged_findings, resolved_findings, and suppressed_findings.

webconf-audit analyze-nginx nginx.conf --baseline webconf-audit-baseline.json

CI can block only new debt with --fail-on-new while leaving existing baseline findings unchanged:

webconf-audit analyze-nginx nginx.conf --baseline webconf-audit-baseline.json --fail-on-new medium

Explicit audit policy

Policies are always opt-in and must be passed explicitly:

webconf-audit policy validate --policy .webconf-audit-policy.yml
webconf-audit policy show --policy .webconf-audit-policy.yml --mode local --server-type nginx --target /etc/nginx/nginx.conf
webconf-audit analyze-nginx /etc/nginx/nginx.conf --policy .webconf-audit-policy.yml

Policies request evidence review scope and opt-in rule tags, but they do not hide findings or raise coverage percentages by themselves.

Control assessment

Assessment is a separate step that consumes a versioned analysis report with embedded resolved policy and rule-execution metadata:

webconf-audit analyze-nginx nginx.conf --policy .webconf-audit-policy.yml --format json > analysis.json
webconf-audit assess --report analysis.json
webconf-audit assess --report analysis.json --format json
webconf-audit assess --report analysis.json --fail-on fail,indeterminate

assess produces a conservative evidence report for resolved policy controls. It does not emit a compliance percentage or certification claim, and a zero-finding run does not automatically become pass.

Assessment exit codes:

  • 0 - assessment was produced and no requested gate status was present.
  • 1 - the report, ledger, policy verification, or output path could not be trusted.
  • 2 - invalid CLI usage.
  • 3 - assessment was produced successfully and a requested --fail-on status was present.

Use --policy with assess only to verify that the supplied policy resolves to the same embedded hashes as the original analysis report. See docs/control-assessment.md.

Local analysis pipeline

Each local analyzer:

  1. Reads the main configuration file passed on the command line.
  2. Resolves includes or rebuilds the inheritance chain.
  3. Builds an effective configuration where the server model requires it.
  4. Runs server-specific rules over the parsed/effective form.
  5. Runs universal rules over a normalized representation shared by all four servers.
  6. Returns a structured result with findings, technical issues, and source metadata.

What each analyzer handles:

  • Nginx — tokenizer, parser, include resolution with glob support and cycle detection, AST traversal, source-location tracking on every directive.
  • ApacheInclude and IncludeOptional resolution, .htaccess discovery from Directory blocks and DocumentRoot, AllowOverride filtering, per-VirtualHost analysis contexts, Location and LocationMatch layering, header merge semantics.
  • Lighttpd — variable expansion, include resolution, include_shell handling (skipped with a warning by default, with explicit opt-in execution via --execute-shell), conditional blocks such as $HTTP["host"] == "...", optional per-host targeted analysis via --host.
  • IIS — safe XML parsing through defusedxml, three-level inheritance chain machine.configapplicationHost.configweb.config, <add> / <remove> / <clear> collection semantics, <location> inheritance, --machine-config option for explicit base config selection, and Windows SChannel TLS registry enrichment by default on Windows hosts. Use --tls-registry <path> for a JSON export from the target IIS server or --no-tls-registry to disable live registry enrichment.

Each finding records severity, description, remediation hint, and a source reference: file and line for text configurations, file and XML path for IIS, observable endpoint or header for external mode.

External analysis

External mode probes a target without access to its configuration. It performs:

  • Port discovery for bare-host targets (default ports: 80, 443, 8080, 8443, 8000, 8888, 3000, 5000, 9443; can be overridden with --ports or disabled with --no-scan-ports).
  • HTTP and HTTPS probing with HEADGET fallback plus a separate OPTIONS flow.
  • TLS enrichment: negotiated protocol and cipher, supported TLS versions, certificate chain completeness, SAN extraction.
  • Server fingerprinting from response headers, default error pages, and reactions to deliberately malformed requests.
  • Sensitive-path probing for paths such as /.git/HEAD, /.env, /.htaccess, /phpinfo.php, /web.config, /robots.txt, /sitemap.xml.
  • Redirect chain analysis: loops, scheme switches, off-domain hops.

External rules cover HTTPS availability and HSTS, common security headers, server identification, cookies, CORS, HTTP methods, sensitive paths, TLS protocol versions, and certificate validity.

Rule catalog

The rule catalog is browsable through the CLI:

webconf-audit list-rules
webconf-audit list-rules --category local --server-type nginx
webconf-audit list-rules --severity high --tag tls
webconf-audit list-rules --format json

Filters: --category (local, external, universal), --server-type (nginx, apache, lighttpd, iis), --severity (critical, high, medium, low, info), --tag.

Use --format json to get a machine-readable inventory with the full RuleMeta payload (rule_id, severity, category, server_type, input_kind, tags, severity_profile, standards, order, etc.). The full inventory and the standards mapping plan live in docs/rule-coverage.md. Severity calibration is documented in docs/severity-methodology.md. Each standard reference includes additive origin and derived_from fields, so independently reviewed mappings can be distinguished from automatic edition alignments.

Control-source coverage ledger

The counted coverage snapshot is stored in the versioned package file src/webconf_audit/data/control_source_coverage.yml. It records stable source and item IDs, applicability, grouped requirements, evidence limitations, registry claims, exclusions, and review provenance. The ledger describes implemented scanner evidence within the documented scope; it is not a claim of certification or target compliance.

Explicit audit policies are a separate layer on top of the ledger. They can select sources and request opt-in evidence, but they do not change the counted coverage snapshot on their own. Per-target status belongs to the separate assessment artifact, not to the coverage percentages shown here.

Validate or inspect the shipped ledger with:

webconf-audit coverage validate
webconf-audit coverage validate --format json
webconf-audit coverage reconcile --check
webconf-audit coverage reconcile --check --format json
webconf-audit coverage reconcile --write
webconf-audit coverage show --source owasp-asvs-5.0.0
webconf-audit coverage show --status partial --format json
webconf-audit coverage export --format markdown

Custom local ledgers can be supplied with --ledger PATH. Exports refuse to overwrite an existing file unless --force is given. The reconcile maintainer command checks or atomically rewrites the tracked coverage documents from the packaged ledger. The generated human-readable view remains available at docs/control-source-coverage-tracker.md; the methodology and headline summary are documented in docs/benchmarks-covering.md.

The catalog currently contains 478 rules:

Category Rules
Local — Nginx 98
Local — Apache 91
Local — Lighttpd 50
Local — IIS 53
Universal (local) 14
External 172

Eleven rules in the inventory above are opt-in policy-review rules. They are excluded from default analyze-* runs and surfaced only when --enable-policy-review is passed. See docs/rule-coverage.md for the rationale.

Reporting

Results are aggregated into a ReportData structure with a summary by severity, analysis mode, server type, and mapped standards. Two output formatters are available:

  • TextFormatter — human-readable command-line output.
  • JsonFormatter — machine-readable output suitable for downstream tooling.

Universal rule findings are deduplicated when a more specific server-specific rule has already reported the same issue at the same location.

Project status

The post-practice project baseline is recorded in docs/project-status.md. It summarizes the current implemented scope, validation status, known boundaries, and the next graduation-project work items.

User-visible changes are tracked in CHANGELOG.md. Release preparation, versioning, tag rules, and package smoke checks are documented in docs/release.md.

Demo

A working local-analysis demo with reproducible Docker-based syntax checks is provided in demo/local_admin/. See demo/local_admin/README.md for the full walkthrough.

A separate defensive validation dataset with public-source-derived config fixtures lives in demo/real_world_configs/. Security-focused known-bad/known-good fixture testing is documented in docs/testing-real-world-configs.md.

Roadmap

The current development plan is tracked in docs/roadmap.md.

Near-term work is focused on parser/effective-configuration precision, standards-driven coverage, safe external probe growth, false-positive reduction, and release preparation. New server-family support should be planned separately after the current four-server core is stable.

Development

Install the development dependency group:

uv sync --group dev --locked

Run the same fast checks as the pull-request CI workflow:

uv run --locked ruff check .
uv run --locked python -m compileall -q src
uv run --locked pytest tests --ignore=tests/integration_external --ignore=tests/integration_local --ignore=tests/integration_rule_coverage --ignore=tests/integration_real_world_cross_mode -q
uv run --locked webconf-audit list-rules
uv run --locked interrogate -c pyproject.toml

The interrogate check enforces a 40% docstring coverage floor over src/ with sensible exclusions (private / dunder / nested helpers). The threshold reflects the project's "default to no comments, only explain non-obvious WHY" convention while still requiring docstrings on module entries, data models, and the public API surface.

Run the Docker-backed integration slice when Docker Engine is available:

uv run --locked pytest tests/integration_external tests/integration_local tests/integration_rule_coverage -q

Run the release check before preparing a public package artifact:

uv run --locked python scripts/release_check.py

The release check builds wheel and source distribution artifacts, installs the wheel into a clean virtual environment, verifies the installed console entry point, and runs a small installed-package smoke test. See docs/release.md for the full checklist.

License

This project is distributed under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

webconf_audit-0.1.4.tar.gz (653.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

webconf_audit-0.1.4-py3-none-any.whl (908.0 kB view details)

Uploaded Python 3

File details

Details for the file webconf_audit-0.1.4.tar.gz.

File metadata

  • Download URL: webconf_audit-0.1.4.tar.gz
  • Upload date:
  • Size: 653.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for webconf_audit-0.1.4.tar.gz
Algorithm Hash digest
SHA256 45dc8c663442ab8678ef4adf37509576c05619e966f9458b81a69385d58ebb8f
MD5 053aa847fbb1173d797687de0977d28d
BLAKE2b-256 ebb09bde7b258483cb1e5e26bb47ed25bb6f0a2e75753bec4b7f61c6b5a46bf0

See more details on using hashes here.

File details

Details for the file webconf_audit-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: webconf_audit-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 908.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for webconf_audit-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 b250c8024d061d70b2c2c2fdc9c9551ca228c26654aec81d8d8cdbcf8b0b3559
MD5 0dd4b0ea4cbaed2b6b712950dc931a27
BLAKE2b-256 c46efd7e9af42d6e6aab0d6cb4f019750df11ebf96716e14a9a574a11859c3bd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page