Web server configuration security audit tool
Project description
webconf-audit
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:
- PyPI: webconf-audit
- Changelog: CHANGELOG.md
- Security policy: SECURITY.md
- Contribution guide: CONTRIBUTING.md
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-onstatus 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:
- Reads the main configuration file passed on the command line.
- Resolves includes or rebuilds the inheritance chain.
- Builds an effective configuration where the server model requires it.
- Runs server-specific rules over the parsed/effective form.
- Runs universal rules over a normalized representation shared by all four servers.
- Returns a structured result with findings, technical issues, and source metadata.
What each analyzer handles:
- Nginx — tokenizer, parser,
includeresolution with glob support and cycle detection, AST traversal, source-location tracking on every directive. - Apache —
IncludeandIncludeOptionalresolution,.htaccessdiscovery fromDirectoryblocks andDocumentRoot,AllowOverridefiltering, per-VirtualHostanalysis contexts,LocationandLocationMatchlayering, header merge semantics. - Lighttpd — variable expansion,
includeresolution,include_shellhandling (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 chainmachine.config→applicationHost.config→web.config,<add>/<remove>/<clear>collection semantics,<location>inheritance,--machine-configoption 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-registryto 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
--portsor disabled with--no-scan-ports). - HTTP and HTTPS probing with
HEAD→GETfallback plus a separateOPTIONSflow. - 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45dc8c663442ab8678ef4adf37509576c05619e966f9458b81a69385d58ebb8f
|
|
| MD5 |
053aa847fbb1173d797687de0977d28d
|
|
| BLAKE2b-256 |
ebb09bde7b258483cb1e5e26bb47ed25bb6f0a2e75753bec4b7f61c6b5a46bf0
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b250c8024d061d70b2c2c2fdc9c9551ca228c26654aec81d8d8cdbcf8b0b3559
|
|
| MD5 |
0dd4b0ea4cbaed2b6b712950dc931a27
|
|
| BLAKE2b-256 |
c46efd7e9af42d6e6aab0d6cb4f019750df11ebf96716e14a9a574a11859c3bd
|