websec-validator 0.2.7__tar.gz → 0.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {websec_validator-0.2.7/src/websec_validator.egg-info → websec_validator-0.2.8}/PKG-INFO +1 -1
- {websec_validator-0.2.7 → websec_validator-0.2.8}/pyproject.toml +1 -1
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/scanners.py +25 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8/src/websec_validator.egg-info}/PKG-INFO +1 -1
- {websec_validator-0.2.7 → websec_validator-0.2.8}/tests/test_hardening.py +28 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/LICENSE +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/README.md +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/setup.cfg +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/__init__.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/briefing.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/calibration.json +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/calibration.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/cli.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/constitution.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/corpus.json +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/dynamic.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/__init__.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/auth.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/authz.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/base.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/client_exposure.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/graphql.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/iac_ci.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/integrations.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/routes.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/schemas.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/stack.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/surface.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/tenant.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/findings.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/probes.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/proof.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/recon.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/report.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/_lib.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/bola-cross-tenant.sh +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/bola-write-verbs.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/compare-roles.sh +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/dlp-bypass-offline.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/forged-token.sh +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/hs256-brute-force.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/jwt-attacks.sh +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/mass-assignment.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/race-conditions.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/rate-limit-burst.sh +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/s3-assess.sh +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/ssrf-probes.sh +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/unauth-baseline.sh +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/webhook-forgery.py +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/FINDINGS-SUMMARY.md.template +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/access-control-matrix.md.template +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/findings-triage.md.template +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/pentest-handover-brief.md.template +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/per-tool-FINDINGS.md.template +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/SOURCES.txt +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/dependency_links.txt +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/entry_points.txt +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/top_level.txt +0 -0
- {websec_validator-0.2.7 → websec_validator-0.2.8}/tests/test_recon.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: websec-validator
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Local-first security recon that briefs your AI coding agent: facts + tailored probe scripts, code-in / artifacts-out. No LLM, no server, no running app.
|
|
5
5
|
Author: Ricardo Accioly
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "websec-validator"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.8"
|
|
8
8
|
description = "Local-first security recon that briefs your AI coding agent: facts + tailored probe scripts, code-in / artifacts-out. No LLM, no server, no running app."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -217,6 +217,27 @@ def _generic_secret(rule: str) -> bool:
|
|
|
217
217
|
return r in _GENERIC_SECRET_RULES or "generic" in r or "entropy" in r
|
|
218
218
|
|
|
219
219
|
|
|
220
|
+
# Secrets matched in DOCUMENTATION / EXAMPLE files are overwhelmingly placeholders, not live
|
|
221
|
+
# credentials — e.g. `curl -H "Authorization: Bearer <token>"` in a README/API doc, or a
|
|
222
|
+
# value in `.env.example`. Tier those to LOW + a verify note (still visible — a real key CAN be
|
|
223
|
+
# pasted into docs by mistake). Dogfooding flagged 4 HIGH curl-auth-header FPs across an API's
|
|
224
|
+
# README + docs/*.md (bug below).
|
|
225
|
+
_DOC_EXT = (".md", ".mdx", ".markdown", ".rst", ".txt", ".adoc")
|
|
226
|
+
_DOC_DIR_MARKERS = ("/docs/", "/doc/", "/examples/", "/example/", "/samples/", "/sample/", "/.github/")
|
|
227
|
+
_DOC_NAME_PREFIX = ("readme", "changelog", "contributing", "license", "authors", "history", "notice")
|
|
228
|
+
_EXAMPLE_SUFFIX = (".example", ".sample", ".dist", ".template", ".tmpl")
|
|
229
|
+
_DOC_NOTE = "in a documentation/example file — almost always a placeholder, verify before treating as real"
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _is_doc_or_example(path: str) -> bool:
|
|
233
|
+
p = (path or "").replace("\\", "/").lower()
|
|
234
|
+
base = p.rsplit("/", 1)[-1]
|
|
235
|
+
return (p.endswith(_DOC_EXT)
|
|
236
|
+
or any(m in p for m in _DOC_DIR_MARKERS)
|
|
237
|
+
or any(base.startswith(m) for m in _DOC_NAME_PREFIX)
|
|
238
|
+
or any(s in base for s in _EXAMPLE_SUFFIX))
|
|
239
|
+
|
|
240
|
+
|
|
220
241
|
def _norm_trivy(data: dict) -> list:
|
|
221
242
|
out = []
|
|
222
243
|
for res in (data.get("Results") or []):
|
|
@@ -231,6 +252,8 @@ def _norm_trivy(data: dict) -> list:
|
|
|
231
252
|
sev, note = _aws_secret_tier(s.get("Match", ""), s.get("Code", "") or "")
|
|
232
253
|
if not sev and _generic_secret(rid):
|
|
233
254
|
sev, note = "MEDIUM", _GENERIC_NOTE
|
|
255
|
+
if _is_doc_or_example(tgt):
|
|
256
|
+
sev, note = "LOW", (note + "; " if note else "") + _DOC_NOTE
|
|
234
257
|
title = f"secret: {s.get('Title') or rid}" + (f" — {note}" if note else "")
|
|
235
258
|
out.append({"tool": "trivy", "category": "secret", "severity": sev or _sev(s.get("Severity") or "HIGH"),
|
|
236
259
|
"key": rid, "file": tgt, "line": s.get("StartLine", 0),
|
|
@@ -250,6 +273,8 @@ def _norm_gitleaks(data) -> list:
|
|
|
250
273
|
sev, note = _aws_secret_tier(x.get("Secret", ""), x.get("Match", ""))
|
|
251
274
|
if not sev and _generic_secret(rule):
|
|
252
275
|
sev, note = "MEDIUM", _GENERIC_NOTE
|
|
276
|
+
if _is_doc_or_example(f):
|
|
277
|
+
sev, note = "LOW", (note + "; " if note else "") + _DOC_NOTE
|
|
253
278
|
title = f"secret: {(x.get('Description') or rule)[:80]}" + (f" — {note}" if note else "")
|
|
254
279
|
out.append({"tool": "gitleaks", "category": "secret", "severity": sev or "HIGH",
|
|
255
280
|
"key": rule, "file": f, "line": x.get("StartLine", 0),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: websec-validator
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Local-first security recon that briefs your AI coding agent: facts + tailored probe scripts, code-in / artifacts-out. No LLM, no server, no running app.
|
|
5
5
|
Author: Ricardo Accioly
|
|
6
6
|
License: MIT
|
|
@@ -171,6 +171,34 @@ class SecretPrecisionTests(unittest.TestCase):
|
|
|
171
171
|
self.assertEqual(hit["confidence"], "MEDIUM")
|
|
172
172
|
|
|
173
173
|
|
|
174
|
+
class DocExampleSecretTests(unittest.TestCase):
|
|
175
|
+
"""0.2.8: secrets in documentation/example files (curl examples in a README, .env.example
|
|
176
|
+
placeholders) tier to LOW + a verify note. Real code files are untouched."""
|
|
177
|
+
|
|
178
|
+
def test_is_doc_or_example(self):
|
|
179
|
+
self.assertTrue(scanners._is_doc_or_example("README.md"))
|
|
180
|
+
self.assertTrue(scanners._is_doc_or_example("docs/API-REFERENCE.md"))
|
|
181
|
+
self.assertTrue(scanners._is_doc_or_example(".env.example"))
|
|
182
|
+
self.assertTrue(scanners._is_doc_or_example("config/settings.sample.json"))
|
|
183
|
+
self.assertFalse(scanners._is_doc_or_example("src/app/route.ts"))
|
|
184
|
+
|
|
185
|
+
def test_gitleaks_doc_secret_to_low_code_stays_high(self):
|
|
186
|
+
rows = [
|
|
187
|
+
{"File": "README.md", "RuleID": "curl-auth-header", "Secret": "x" * 30, "Match": "Authorization: Bearer x", "StartLine": 1},
|
|
188
|
+
{"File": "src/server.ts", "RuleID": "private-key", "Secret": "-----BEGIN", "Match": "-----BEGIN", "StartLine": 1},
|
|
189
|
+
]
|
|
190
|
+
by = {r["file"]: r for r in scanners._norm_gitleaks(rows)}
|
|
191
|
+
self.assertEqual(by["README.md"]["severity"], "LOW")
|
|
192
|
+
self.assertIn("documentation/example", by["README.md"]["title"])
|
|
193
|
+
self.assertEqual(by["src/server.ts"]["severity"], "HIGH") # real code file untouched
|
|
194
|
+
|
|
195
|
+
def test_trivy_doc_secret_to_low(self):
|
|
196
|
+
data = {"Results": [{"Target": "docs/SECURITY.md", "Secrets": [
|
|
197
|
+
{"RuleID": "curl-auth-header", "Title": "Auth header", "Match": "Bearer x", "StartLine": 1}]}]}
|
|
198
|
+
secs = [f for f in scanners._norm_trivy(data) if f["category"] == "secret"]
|
|
199
|
+
self.assertEqual(secs[0]["severity"], "LOW")
|
|
200
|
+
|
|
201
|
+
|
|
174
202
|
class CookieCoverageTests(unittest.TestCase):
|
|
175
203
|
"""0.2.7: extract auth cookie names so the forged-token engine covers cookie-ONLY apps."""
|
|
176
204
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/client_exposure.py
RENAMED
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/graphql.py
RENAMED
|
File without changes
|
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/integrations.py
RENAMED
|
File without changes
|
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/schemas.py
RENAMED
|
File without changes
|
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/surface.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/_lib.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/s3-assess.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|