A lightweight, fast and extensible CLI tool to automate security posture checks during Web Application Penetration Testing (WAPT) activities.
Waptly scans one or more targets concurrently and outputs a structured JSON report, helping pentesters map the webapp risk surface.
Caution
Waptly is intended for authorized security testing only.
Do not use against systems you do not own or have explicit permission to test.
Checks include (but are not limited to):
| Module | Description |
|---|---|
http_security_headers |
Detects missing security headers (CSP, HSTS, X-Frame-Options, etc.) |
waf_detection |
Fingerprints WAF presence via response headers (Cloudflare, Akamai, AWS, etc.) |
tls |
Checks TLS version, certificate expiry, self-signed certs and weak ciphers |
robots_txt |
Parses robots.txt and flags sensitive paths exposed to crawlers |
http_methods |
Probes dangerous HTTP methods (TRACE, PUT, DELETE, CONNECT) |
waptly is primarily designed as a component to be integrated into red team automation workflows, with the purpose of assisting in mapping the attack surface of a web application.
It helps generate actionable insights to be further investigated during penetration testing activities.
The output already includes findings that can be directly incorporated into the final report, such as missing HTTP security headers.
waptly is not intended to replace established WAPT tools such as Nuclei, Gobuster or Burp Suite.
On the contrary, it is designed to complement them.
waptly is also highly effective as a tool for AI agents operating via CLI environments, such as Claude Code or Codex.
It is possible either to create a customized skill file for the agent or to have the agent invoke the tool directly,
for example, when using Codex:
codex --full-auto "run the command `./waptly https://pentest-ground.com:4280/` and write a summary of the output to FINDINGS.md"You can directly download the latest binary release for your target architecture,
however, the recommended way to run waptly is via Docker:
docker run ghcr.io/r3drun3/waptly:v0.1.4 <target_1> <target_2> <target_n>video-demo.mp4
Tip
By default, the JSON output only includes failed checks, keeping the report focused and noise-free.
Pass the --verbose (or -v) flag to include all checks regardless of their result.
Example: waptly --verbose https://example.com
Waptly outputs a single JSON report to stdout, here is an example:
{
"version": "v0.1.4",
"generated_at": "2026-04-27T15:54:15Z",
"targets": [
{
"target": "https://pentest-ground.com:4280/",
"checks": [
{
"check": "cookie_security",
"passed": false,
"details": {
"findings": [
{
"name": "security",
"missing_secure": true,
"missing_http_only": true,
"missing_same_site": true,
"severity": "high"
},
{
"name": "PHPSESSID",
"missing_secure": true,
"missing_http_only": true,
"missing_same_site": true,
"severity": "high"
}
],
"total_cookies_checked": 2
}
},
{
"check": "error_handling",
"passed": true,
"details": {
"results": [
{
"payload_type": "large_payload",
"path": "/",
"triggered_500": false
},
{
"payload_type": "malformed_json",
"path": "/",
"triggered_500": false
},
{
"payload_type": "unicode_fuzz",
"path": "/",
"triggered_500": false
},
{
"payload_type": "sql_injection",
"path": "/?id=' OR 1=1--",
"triggered_500": false
},
{
"payload_type": "cmd_injection",
"path": "/?q=;cat /etc/passwd",
"triggered_500": false
}
]
}
},
{
"check": "exposed_files",
"passed": false,
"details": {
"base_url": "https://pentest-ground.com:4280",
"found": [
{
"path": "/phpinfo.php",
"status_code": 200,
"content_type": "text/html; charset=UTF-8",
"body_preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>\n<style type=\"text/css\">\nbody {background-color: #fff; co...",
"severity": "high"
}
],
"found_count": 1,
"probed": 30
}
},
{
"check": "http_security_headers",
"passed": false,
"details": {
"missing": {
"Content-Security-Policy": "Mitigates XSS and data injection attacks",
"Cross-Origin-Opener-Policy": "Isolates browsing context against XS-Leaks",
"Cross-Origin-Resource-Policy": "Controls cross-origin resource sharing",
"Permissions-Policy": "Restricts browser feature access",
"Referrer-Policy": "Controls referrer information leakage",
"Strict-Transport-Security": "Enforces HTTPS (HSTS)",
"X-Content-Type-Options": "Prevents MIME-type sniffing",
"X-Frame-Options": "Protects against clickjacking"
},
"present": {}
}
},
{
"check": "http_methods",
"passed": false,
"details": {
"dangerous_methods": [
{
"method": "TRACK",
"status_code": 200,
"risk": "Variant of TRACE, used by older IIS servers",
"severity": "high",
"advertised_by_options": false
},
{
"method": "PUT",
"status_code": 200,
"risk": "Arbitrary file upload may be possible",
"severity": "critical",
"advertised_by_options": false
},
{
"method": "DELETE",
"status_code": 200,
"risk": "Destructive operations may be possible",
"severity": "critical",
"advertised_by_options": false
},
{
"method": "CONNECT",
"status_code": 400,
"risk": "Server may be usable as an HTTP proxy",
"severity": "high",
"advertised_by_options": false
},
{
"method": "PATCH",
"status_code": 200,
"risk": "Partial resource modification may be possible",
"severity": "medium",
"advertised_by_options": false
}
],
"issues": [
"TRACK enabled (HTTP 200) — Variant of TRACE, used by older IIS servers",
"PUT enabled (HTTP 200) — Arbitrary file upload may be possible",
"DELETE enabled (HTTP 200) — Destructive operations may be possible",
"CONNECT enabled (HTTP 400) — Server may be usable as an HTTP proxy",
"PATCH enabled (HTTP 200) — Partial resource modification may be possible"
],
"options_advertised": null
}
},
{
"check": "https_redirect",
"passed": false,
"details": {
"http_status": 400,
"location": "",
"message": "No valid HTTP to HTTPS redirect."
}
},
{
"check": "open_redirect",
"passed": true,
"details": {
"findings": []
}
},
{
"check": "robots_txt",
"passed": true,
"details": {
"entries": [
{
"user_agent": "*",
"disallowed": [
"/"
]
}
],
"found": true,
"raw_lines": [
"User-agent: *",
"Disallow: /"
],
"robots_url": "https://pentest-ground.com:4280/robots.txt",
"sensitive_paths": null,
"status_code": 200
}
},
{
"check": "server_banner",
"passed": false,
"details": {
"findings": [
{
"header": "Server",
"value": "nginx/1.29.8",
"technology": "nginx",
"versions": [
"1.29.8"
]
},
{
"header": "X-Powered-By",
"value": "PHP/8.5.5",
"technology": "PHP",
"versions": [
"8.5.5"
]
}
],
"leaking": true,
"technologies": [
"nginx",
"PHP"
],
"versions": [
"1.29.8",
"8.5.5"
]
}
},
{
"check": "tls",
"passed": true,
"details": {
"certificates": [
{
"days_until_expiry": 56,
"dns_names": [
"pentest-ground.com"
],
"expired": false,
"is_ca": false,
"issuer": "E7",
"not_after": "2026-06-23T03:10:40Z",
"not_before": "2026-03-25T03:10:41Z",
"self_signed": false,
"signature_algorithm": "ECDSA-SHA384",
"subject": "pentest-ground.com"
},
{
"dns_names": null,
"is_ca": true,
"issuer": "ISRG Root X1",
"not_after": "2027-03-12T23:59:59Z",
"not_before": "2024-03-13T00:00:00Z",
"signature_algorithm": "SHA256-RSA",
"subject": "E7"
}
],
"cipher_suite": "TLS_AES_128_GCM_SHA256",
"issues": [],
"tls_version": "TLS 1.3",
"weak_cipher": false
}
},
{
"check": "waf_detection",
"passed": false,
"details": {
"detected": [],
"evidence": {},
"waf_detected": false
}
}
]
}
]
}- Create
checks/your_check.goin thechecks/package - Implement the Check interface
- Register it via
init()(no changes tomain.goneeded)
