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.
Files changed (59) hide show
  1. {websec_validator-0.2.7/src/websec_validator.egg-info → websec_validator-0.2.8}/PKG-INFO +1 -1
  2. {websec_validator-0.2.7 → websec_validator-0.2.8}/pyproject.toml +1 -1
  3. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/scanners.py +25 -0
  4. {websec_validator-0.2.7 → websec_validator-0.2.8/src/websec_validator.egg-info}/PKG-INFO +1 -1
  5. {websec_validator-0.2.7 → websec_validator-0.2.8}/tests/test_hardening.py +28 -0
  6. {websec_validator-0.2.7 → websec_validator-0.2.8}/LICENSE +0 -0
  7. {websec_validator-0.2.7 → websec_validator-0.2.8}/README.md +0 -0
  8. {websec_validator-0.2.7 → websec_validator-0.2.8}/setup.cfg +0 -0
  9. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/__init__.py +0 -0
  10. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/briefing.py +0 -0
  11. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/calibration.json +0 -0
  12. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/calibration.py +0 -0
  13. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/cli.py +0 -0
  14. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/constitution.py +0 -0
  15. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/corpus.json +0 -0
  16. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/dynamic.py +0 -0
  17. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/__init__.py +0 -0
  18. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/auth.py +0 -0
  19. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/authz.py +0 -0
  20. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/base.py +0 -0
  21. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/client_exposure.py +0 -0
  22. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/graphql.py +0 -0
  23. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/iac_ci.py +0 -0
  24. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/integrations.py +0 -0
  25. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/routes.py +0 -0
  26. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/schemas.py +0 -0
  27. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/stack.py +0 -0
  28. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/surface.py +0 -0
  29. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/extractors/tenant.py +0 -0
  30. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/findings.py +0 -0
  31. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/probes.py +0 -0
  32. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/proof.py +0 -0
  33. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/recon.py +0 -0
  34. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/report.py +0 -0
  35. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/_lib.py +0 -0
  36. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/bola-cross-tenant.sh +0 -0
  37. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/bola-write-verbs.py +0 -0
  38. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/compare-roles.sh +0 -0
  39. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/dlp-bypass-offline.py +0 -0
  40. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/forged-token.sh +0 -0
  41. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/hs256-brute-force.py +0 -0
  42. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/jwt-attacks.sh +0 -0
  43. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/mass-assignment.py +0 -0
  44. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/race-conditions.py +0 -0
  45. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/rate-limit-burst.sh +0 -0
  46. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/s3-assess.sh +0 -0
  47. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/ssrf-probes.sh +0 -0
  48. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/unauth-baseline.sh +0 -0
  49. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/probes/webhook-forgery.py +0 -0
  50. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/FINDINGS-SUMMARY.md.template +0 -0
  51. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/access-control-matrix.md.template +0 -0
  52. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/findings-triage.md.template +0 -0
  53. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/pentest-handover-brief.md.template +0 -0
  54. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator/templates/reports/per-tool-FINDINGS.md.template +0 -0
  55. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/SOURCES.txt +0 -0
  56. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/dependency_links.txt +0 -0
  57. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/entry_points.txt +0 -0
  58. {websec_validator-0.2.7 → websec_validator-0.2.8}/src/websec_validator.egg-info/top_level.txt +0 -0
  59. {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.7
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"
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.7
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