Deterministic web security smoke tests for preview, staging, and pre-deploy URLs.
Project description
surface-audit
Deterministic security smoke tests for staging, preview, and pre-deploy web apps.
surface-audit sends a small, bounded set of safe probes at a known
URL and turns the result into CI-friendly findings, SARIF, Markdown,
HTML, and JSON reports. It is designed for teams that want to catch
security regressions in headers, TLS, redirects, cookies, CORS, exposed
files, and other surface-level mistakes before they promote a build.
⚠️ Authorized use only. This tool sends real HTTP requests to the target. Only run it against systems you own or have explicit written permission to test. See
SECURITY.md.
Why Teams Use It
- Safe by default — bounded checks against a known URL, not a crawler and not an exploit framework.
- Regression-oriented — baseline suppression and report diff help answer "what got worse?" instead of just "what exists?"
- CI-native —
--fail-on, SARIF, Markdown, HTML, and JSON all fit cleanly into pull requests, code scanning, and release gates. - LLM-safe MCP support — the optional MCP server exposes only a host allow-listed interface.
- Extensible — checks and renderers are pluggable via entry points.
- Supply-chain aware — PyPI Trusted Publishing, Sigstore signatures, GitHub Releases, and CycloneDX SBOMs are built into the release flow.
Use It When
- you have a staging, preview, or pre-production URL
- you want a deterministic security gate in CI
- you care about security regressions between two deployments
- you want machine-readable output for SARIF, dashboards, or PR comments
Reach for Other Tools When
- you need full crawling or spidering
- you need authenticated scanning workflows
- you want exploit confirmation or a broad template corpus
That positioning is deliberate: surface-audit is strongest as a
pre-deploy security smoke test, not as a full DAST platform.
Quick Start
pipx install surface-audit
surface-audit scan https://preview.example.com \
--scope-host preview.example.com \
--fail-on HIGH
Detailed installation: docs/INSTALL.md.
Distribution Options
- PyPI — best when you want the CLI in
pipx, a virtualenv, or your own Python-based tooling. - GHCR — best when your CI prefers a prebuilt container image over installing Python dependencies at runtime.
- GitHub Action — best when a preview-environment workflow already lives in GitHub Actions and you want the shortest integration path.
Container-first teams can use the published GHCR image on tagged releases:
docker run --rm ghcr.io/dev-ugurkontel/surface-audit:latest \
scan https://preview.example.com --fail-on HIGH
Use the GitHub Action @v1 tag for the stable major line, or pin an
exact action release such as @v1.0.2 when you want fully reproducible
workflow inputs. Tagged releases also publish GitHub Release artifacts,
CycloneDX SBOMs, and Sigstore signatures.
More end-to-end patterns: docs/RECIPES.md.
Security Regression Diff
# Capture a baseline once
surface-audit scan https://preview.example.com \
--output reports/baseline.json \
--format json
# Gate only on newly introduced HIGH+ findings
surface-audit scan https://preview.example.com \
--baseline reports/baseline.json \
--fail-on HIGH
# Or diff two reports explicitly
surface-audit diff reports/before.json reports/after.json \
--output reports/diff.json \
--fail-on-new
GitHub Action
The repository ships an action at the repo root so you can run the scan in a preview-environment workflow without hand-rolling install steps:
- name: Run surface-audit
uses: dev-ugurkontel/surface-audit@v1
with:
target: ${{ steps.preview.outputs.url }}
scope-hosts: preview.example.com
output: reports/surface-audit.sarif
format: sarif
fail-on: HIGH
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: reports/surface-audit.sarif
More end-to-end patterns: docs/RECIPES.md.
Sample Output
Target: https://preview.example.com/
Summary: HIGH 1 MEDIUM 2 LOW 1
HIGH security-headers Missing Content-Security-Policy header
MEDIUM auth-cookies Cookie 'sessionid' missing SameSite
MEDIUM security-txt Missing /.well-known/security.txt
LOW directory-listing Auto-generated index page exposed
Built-in checks
| Check ID | OWASP | Summary |
|---|---|---|
security-headers |
A05 | Missing and weakly-configured HSTS / CSP / XFO / Referrer / Permissions |
ssl-tls |
A02 | Weak ciphers or obsolete TLS versions |
https-redirect |
A02 | Plain HTTP does not redirect to HTTPS |
cross-origin-isolation |
A05 | Missing COOP / COEP / CORP isolation headers |
xss-reflection |
A03 | Query-string input reflected without output encoding |
sql-injection |
A03 | Database error messages leaked on meta-character input |
csrf |
A01 | Mutating HTML forms without a recognizable anti-CSRF token |
auth-cookies |
A07 | Cookies missing Secure / HttpOnly / SameSite |
open-redirect |
A01 | Query parameters that allow off-origin 30x redirects |
misconfiguration |
A05 | Well-known exposed paths (.env, .git, admin consoles) |
directory-listing |
A05 | Auto-generated directory index pages |
cors |
A05 | Permissive CORS reflections and wildcard-with-credentials |
security-txt |
A09 | Missing /.well-known/security.txt (RFC 9116) |
Run surface-audit list-checks to see what is registered in your
environment (including any third-party plugins).
Usage
# Save a JSON report and fail CI on HIGH+ findings
surface-audit scan https://example.com \
--output reports/example.json --format json --fail-on HIGH
# Emit SARIF for GitHub Advanced Security
surface-audit scan https://example.com \
--output reports/example.sarif --format sarif
# Run only a subset of checks
surface-audit scan https://example.com \
--enable security-headers --enable ssl-tls
Full CLI and library reference: docs/USAGE.md.
MCP integration
pip install "surface-audit[mcp]"
surface-audit mcp-serve --allow-host staging.example.com
This exposes scan, list_checks, list_formats, and render_report
tools to local MCP clients while keeping scans gated behind an explicit
host allow-list.
Project Site
The project site highlights the smoke-test workflow, GitHub Action, sample artifacts, and core adoption patterns:
Download trends remain available via PyPI Stats.
Library example
import asyncio
from surface_audit import Scanner, ScannerConfig
async def main() -> None:
report = await Scanner(
"https://example.com",
config=ScannerConfig(max_concurrency=4, timeout=5.0),
).run()
for finding in report.findings:
print(finding.severity.value, finding.check_id, finding.title)
asyncio.run(main())
Extend it
Any package shipping an entry point under surface_audit.checks adds a
check. A starter template for third-party checks lives under
examples/plugin-template:
# your-plugin/pyproject.toml
[project.entry-points."surface_audit.checks"]
cors_wildcard = "my_checks.cors:PermissiveCORSCheck"
See docs/ARCHITECTURE.md for layering, SOLID
scorecard, and design patterns.
Documentation
docs/INSTALL.md— per-platform installationdocs/USAGE.md— CLI, library, and CI recipesdocs/RECIPES.md— preview, SARIF, baseline, MCP, and action recipesdocs/ARCHITECTURE.md— layering and extension pointsdocs/SCHEMA.md— JSON report contractexamples/plugin-template— starter template for third-party checksSUPPORT.md— where to ask questions and report the right thingCONTRIBUTING.md— development workflowSECURITY.md— vulnerability disclosureCODE_OF_CONDUCT.md— community expectations
Development
make install # set up .venv with dev extras
make all # ruff + mypy + bandit + pytest
CI runs on every push across Python 3.10 – 3.13 — see
.github/workflows/ci.yml.
License
Apache License 2.0 — Copyright © 2026 Uğur Kontel. See also
NOTICE for attribution requirements that apply to
redistributions.
surface-audit is an open-source project from
Fillbyte.
Project details
Release history Release notifications | RSS feed
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 surface_audit-1.0.2.tar.gz.
File metadata
- Download URL: surface_audit-1.0.2.tar.gz
- Upload date:
- Size: 102.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a884a84c3ab50deb6ffc591aa612c7fc7ef0f6decf10d0aa43cb69433f68d66
|
|
| MD5 |
e720af324605d3a3aa6cda6f9e6f2a98
|
|
| BLAKE2b-256 |
347240204bae35591f8ad4e808ee318b561a185113c52aeca2cf88c976b64f92
|
Provenance
The following attestation bundles were made for surface_audit-1.0.2.tar.gz:
Publisher:
release.yml on dev-ugurkontel/surface-audit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
surface_audit-1.0.2.tar.gz -
Subject digest:
1a884a84c3ab50deb6ffc591aa612c7fc7ef0f6decf10d0aa43cb69433f68d66 - Sigstore transparency entry: 1343759502
- Sigstore integration time:
-
Permalink:
dev-ugurkontel/surface-audit@db10d9cc828968e773db07bcda29a3af2def0562 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/dev-ugurkontel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@db10d9cc828968e773db07bcda29a3af2def0562 -
Trigger Event:
push
-
Statement type:
File details
Details for the file surface_audit-1.0.2-py3-none-any.whl.
File metadata
- Download URL: surface_audit-1.0.2-py3-none-any.whl
- Upload date:
- Size: 64.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bd8b6f276677d3275f6bf53b01deedb4e0e4020d79ee74e86a5e4ce92a4ca9c
|
|
| MD5 |
9ce8a3311ae7f002998a41a9739260c3
|
|
| BLAKE2b-256 |
5e982a995578155fafaccfe9aebf478ae2d284786832a840d1494a01153708d8
|
Provenance
The following attestation bundles were made for surface_audit-1.0.2-py3-none-any.whl:
Publisher:
release.yml on dev-ugurkontel/surface-audit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
surface_audit-1.0.2-py3-none-any.whl -
Subject digest:
3bd8b6f276677d3275f6bf53b01deedb4e0e4020d79ee74e86a5e4ce92a4ca9c - Sigstore transparency entry: 1343759512
- Sigstore integration time:
-
Permalink:
dev-ugurkontel/surface-audit@db10d9cc828968e773db07bcda29a3af2def0562 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/dev-ugurkontel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@db10d9cc828968e773db07bcda29a3af2def0562 -
Trigger Event:
push
-
Statement type: