@aegis-scan/skills 0.5.0 → 0.5.2
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.
- package/ATTRIBUTION.md +93 -0
- package/package.json +1 -1
- package/sbom.cdx.json +1 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/.claude-plugin/plugin.json +108 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/CHANGELOG.md +878 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/README.md +9 -3
- package/skills/compliance/aegis-native/brutaler-anwalt/SKILL.md +93 -14
- package/skills/compliance/aegis-native/brutaler-anwalt/commands/audit.md +193 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/commands/avv-redline.md +246 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/commands/az-verify.md +155 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/commands/cold-start.md +157 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/commands/dsar-respond.md +180 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/commands/health.md +50 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/commands/simulate.md +158 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/hooks/post_write.py +315 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/hooks/prompt_submit.py +144 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/hooks/session_start.py +57 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/hooks/triggers.json +191 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/INDEX.md +102 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/abmahn-templates.md +1 -1
- package/skills/compliance/aegis-native/brutaler-anwalt/references/aegis-integration.md +60 -5
- package/skills/compliance/aegis-native/brutaler-anwalt/references/audit-patterns.md +745 -11
- package/skills/compliance/aegis-native/brutaler-anwalt/references/az-auffuellung-batch1.md +468 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/bgh-urteile.md +106 -30
- package/skills/compliance/aegis-native/brutaler-anwalt/references/branchenrecht.md +247 -2
- package/skills/compliance/aegis-native/brutaler-anwalt/references/checklisten.md +75 -2
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-aufsichtsbehoerden-taetigkeitsberichte-2024.md +310 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-bussgeld-argumentations-layer.md +598 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-dsk-beschluesse.md +346 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/AGG/audit-relevance.md +76 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/AGG/paragraphs.md +115 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/AMG/audit-relevance.md +58 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/AMG/paragraphs.md +95 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/ArbZG/audit-relevance.md +60 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/ArbZG/paragraphs.md +90 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/BetrVG/audit-relevance.md +73 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/BetrVG/paragraphs.md +114 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/DDG/audit-relevance.md +72 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/DDG/paragraphs.md +103 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/DiGAV/audit-relevance.md +65 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/DiGAV/paragraphs.md +102 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/ElektroG/audit-relevance.md +66 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/ElektroG/paragraphs.md +108 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/FernUSG/audit-relevance.md +80 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/FernUSG/paragraphs.md +102 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/GeschGehG/audit-relevance.md +89 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/GeschGehG/paragraphs.md +107 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/GwG/audit-relevance.md +62 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/GwG/paragraphs.md +119 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/HWG/audit-relevance.md +70 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/HWG/paragraphs.md +125 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/HinSchG/audit-relevance.md +70 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/HinSchG/paragraphs.md +116 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/INDEX.md +152 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/KWG/audit-relevance.md +64 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/KWG/paragraphs.md +110 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/LFGB/audit-relevance.md +63 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/LFGB/paragraphs.md +90 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/MPDG/audit-relevance.md +61 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/MPDG/paragraphs.md +96 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/NachwG/audit-relevance.md +54 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/NachwG/paragraphs.md +82 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/PAngV/audit-relevance.md +76 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/PAngV/paragraphs.md +86 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/RDG/audit-relevance.md +84 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/RDG/paragraphs.md +114 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/TDDDG/audit-relevance.md +92 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/TDDDG/paragraphs.md +91 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/UrhG-UrhDaG/audit-relevance.md +85 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/UrhG-UrhDaG/paragraphs.md +166 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/VDuG/audit-relevance.md +71 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/VDuG/paragraphs.md +102 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/VERIFICATION-NOTES.md +111 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/VVG/audit-relevance.md +65 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/VVG/paragraphs.md +101 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/VerpackG/audit-relevance.md +62 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/VerpackG/paragraphs.md +120 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/WpHG/audit-relevance.md +64 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/WpHG/paragraphs.md +120 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/ZAG/audit-relevance.md +68 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/de-statute-tier1/ZAG/paragraphs.md +110 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/dsgvo.md +55 -8
- package/skills/compliance/aegis-native/brutaler-anwalt/references/eu-edpb-guidelines.md +505 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/eu-eugh-dsgvo-schadensersatz.md +223 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BDSG/audit-relevance.md +31 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BFSG/audit-relevance.md +39 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BGB/audit-relevance.md +42 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/DDG/audit-relevance.md +28 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/DSGVO/audit-relevance.md +35 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/articles.md +4 -1
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/audit-relevance.md +139 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/gpai-pflichten.md +102 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/hochrisiko-annex-iii.md +134 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/sanktionen-art-99.md +97 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/transparenz-art-50.md +120 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/uebergangsfristen.md +109 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/CER-2022-2557/articles.md +42 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/CRA-2024-2847/articles.md +87 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/CSDDD-2024-1760/articles.md +43 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/CSRD-2022-2464/articles.md +42 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DGA-2022-868/articles.md +53 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DMA-2022-1925/articles.md +55 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DORA-2022-2554/articles.md +164 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DORA-2022-2554/audit-relevance.md +86 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/articles.md +3 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/audit-relevance.md +110 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/notice-and-action.md +138 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/small-platform-pflichten.md +109 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/trusted-flaggers.md +77 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/vlop-vlose.md +130 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/Data-Act-2023-2854/articles.md +102 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/Data-Act-2023-2854/audit-relevance.md +77 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/MiCA-2023-1114/articles.md +124 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/MiCA-2023-1114/audit-relevance.md +85 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/NIS2-2022-2555/articles.md +101 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/ProdHaftRL-2024-2853/articles.md +68 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/eIDAS-2024-1183/articles.md +43 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/Finance/KWG.md +52 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/Finance/PSD2.md +67 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/Finance/ZAG.md +50 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/GlueStV/articles.md +86 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/HGB-AO/audit-relevance.md +27 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/HinSchG/articles.md +96 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/JuSchG-JMStV/articles.md +86 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/KritisDachG/articles.md +39 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/LkSG/articles.md +90 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/MedTech/DiGAV.md +60 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/MedTech/IVDR-2017-746.md +51 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/MedTech/MDR-2017-745.md +85 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/NIS2UmsuCG-BSIG/articles.md +53 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/StGB/relevante-paragraphen.md +157 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/TDDDG/audit-relevance.md +33 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/TDDDG/paragraphs.md +3 -2
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/TKG/articles.md +73 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/UWG/audit-relevance.md +39 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/UWG/paragraphs.md +71 -3
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/VERIFICATION-STATUS.md +266 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/VSBG/audit-relevance.md +37 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/ePrivacy-RL-2002-58/articles.md +92 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/ePrivacy-RL-2002-58/audit-relevance.md +62 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/it-recht.md +115 -9
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/INDEX.md +1 -1
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/ai/anthropic-dpa.md +87 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/astro/cookie-banner-pattern.md +202 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/astro/dse-section-pattern.md +198 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/astro/tracking-server-endpoint.md +193 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/auth/auth0-tom.md +92 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/auth/clerk-tom.md +84 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/django/auth-cookies-pattern.md +295 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/django/cookie-banner-pattern.md +318 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/django/gdpr-cleanup-celery.md +339 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/express/cookie-banner-pattern.md +237 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/express/gdpr-routes-pattern.md +256 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/express/helmet-csp-pattern.md +207 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/laravel/agb-versioning-pattern.md +305 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/laravel/cookie-banner-pattern.md +287 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/laravel/gdpr-models-pattern.md +290 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/laravel/tracking-config-pattern.md +263 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nest/auth-pattern.md +265 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nest/cookie-banner-pattern.md +255 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nest/gdpr-cleanup-cron.md +244 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nest/tracking-interceptor.md +239 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nextjs/api-route-bearer-auth.md +103 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nextjs/dynamic-rendering-headers.md +83 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nextjs/env-driven-tracking.md +135 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/rails/cookie-banner-pattern.md +294 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/rails/devise-dsgvo-pattern.md +262 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/rails/gdpr-anonymization-pattern.md +283 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/react/consent-gate-pattern.md +99 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/react/cookie-banner-pattern.md +204 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/strapi/cms-pii-pattern.md +301 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/strapi/notice-and-action-plugin.md +371 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/svelte/cookie-banner-pattern.md +234 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/svelte/dse-section-pattern.md +231 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/svelte/sveltekit-server-hooks-pattern.md +217 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/tracking/google-analytics-consent.md +129 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/tracking/posthog-consent.md +79 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/vue/cookie-banner-pattern.md +208 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/vue/dse-i18n-pattern.md +204 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/vue/nuxt-vs-vue-only-pattern.md +197 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/vue/tracking-pinia-pattern.md +211 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/strafrecht-steuer.md +1 -1
- package/skills/compliance/aegis-native/brutaler-anwalt/references/streitwerte.json +176 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/DSFA-template.md +80 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/VVT-template-file-upload.md +98 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-EN-international.md +267 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-anhang-Audit-Klausel-Varianten.md +148 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-anhang-CH-revDSG.md +127 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-anhang-SCC-module2-controller-processor.md +180 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-anhang-SCC-module3-processor-subprocessor.md +144 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-anhang-Sub-Processor-List.md +114 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-anhang-TOMs.md +197 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-anhang-UK-IDTA.md +131 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/AVV-standard-DE.md +288 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates-avv-layer/Joint-Controller-Vertrag-Art-26.md +265 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/scripts/health-check.sh +190 -48
- package/skills/compliance/aegis-native/brutaler-anwalt/scripts/test-triggers.sh +145 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/settings.json +90 -0
- package/skills/defensive/permoon-fork/README.md +40 -0
- package/skills/defensive/permoon-fork/multi-model-consolidation/SKILL.md +47 -0
- package/skills/defensive/permoon-fork/multi-model-severity/SKILL.md +34 -0
- package/skills/defensive/permoon-fork/multi-model-system-prompt/SKILL.md +40 -0
- package/skills/foundation/aegis-native/aegis-handover-writer/SKILL.md +1 -1
- package/skills/foundation/aegis-native/aegis-quality-gates/SKILL.md +1 -1
- package/skills/offensive/airecon-fork/ctf-crypto/SKILL.md +260 -0
- package/skills/offensive/airecon-fork/ctf-crypto-modern-ciphers/SKILL.md +688 -0
- package/skills/offensive/airecon-fork/ctf-forensics/SKILL.md +253 -0
- package/skills/offensive/airecon-fork/ctf-forensics-network/SKILL.md +480 -0
- package/skills/offensive/airecon-fork/ctf-heap-advanced/SKILL.md +336 -0
- package/skills/offensive/airecon-fork/ctf-pwn/SKILL.md +294 -0
- package/skills/offensive/airecon-fork/ctf-pwn-rop-and-shellcode/SKILL.md +392 -0
- package/skills/offensive/airecon-fork/ctf-reversing/SKILL.md +284 -0
- package/skills/offensive/airecon-fork/frameworks-django/SKILL.md +268 -0
- package/skills/offensive/airecon-fork/frameworks-dotnet/SKILL.md +280 -0
- package/skills/offensive/airecon-fork/frameworks-express/SKILL.md +266 -0
- package/skills/offensive/airecon-fork/frameworks-fastapi/SKILL.md +193 -0
- package/skills/offensive/airecon-fork/frameworks-flask/SKILL.md +297 -0
- package/skills/offensive/airecon-fork/frameworks-laravel/SKILL.md +260 -0
- package/skills/offensive/airecon-fork/frameworks-nextjs/SKILL.md +230 -0
- package/skills/offensive/airecon-fork/frameworks-php/SKILL.md +271 -0
- package/skills/offensive/airecon-fork/frameworks-rails/SKILL.md +269 -0
- package/skills/offensive/airecon-fork/frameworks-spring/SKILL.md +245 -0
- package/skills/offensive/airecon-fork/frameworks-wordpress/SKILL.md +348 -0
- package/skills/offensive/airecon-fork/payloads-command-injection/SKILL.md +459 -0
- package/skills/offensive/airecon-fork/payloads-http-parameter-pollution/SKILL.md +129 -0
- package/skills/offensive/airecon-fork/payloads-ldap-injection/SKILL.md +100 -0
- package/skills/offensive/airecon-fork/payloads-lfi/SKILL.md +485 -0
- package/skills/offensive/airecon-fork/payloads-sqli/SKILL.md +419 -0
- package/skills/offensive/airecon-fork/payloads-ssrf/SKILL.md +125 -0
- package/skills/offensive/airecon-fork/payloads-ssti/SKILL.md +443 -0
- package/skills/offensive/airecon-fork/payloads-xss/SKILL.md +447 -0
- package/skills/offensive/airecon-fork/payloads-xxe/SKILL.md +172 -0
- package/skills/offensive/airecon-fork/postexploit-ad-credential-attacks/SKILL.md +306 -0
- package/skills/offensive/airecon-fork/postexploit-container-escape/SKILL.md +299 -0
- package/skills/offensive/airecon-fork/postexploit-credential-dumping/SKILL.md +249 -0
- package/skills/offensive/airecon-fork/postexploit-lateral-movement/SKILL.md +194 -0
- package/skills/offensive/airecon-fork/postexploit-linux-privesc/SKILL.md +252 -0
- package/skills/offensive/airecon-fork/postexploit-netexec-workflow/SKILL.md +302 -0
- package/skills/offensive/airecon-fork/postexploit-pivoting/SKILL.md +205 -0
- package/skills/offensive/airecon-fork/postexploit-windows-privesc/SKILL.md +210 -0
- package/skills/offensive/airecon-fork/protocols-active-directory/SKILL.md +314 -0
- package/skills/offensive/airecon-fork/protocols-dns/SKILL.md +203 -0
- package/skills/offensive/airecon-fork/protocols-ftp/SKILL.md +159 -0
- package/skills/offensive/airecon-fork/protocols-graphql/SKILL.md +648 -0
- package/skills/offensive/airecon-fork/protocols-kerberos/SKILL.md +168 -0
- package/skills/offensive/airecon-fork/protocols-ldap/SKILL.md +245 -0
- package/skills/offensive/airecon-fork/protocols-rdp/SKILL.md +186 -0
- package/skills/offensive/airecon-fork/protocols-smb/SKILL.md +191 -0
- package/skills/offensive/airecon-fork/protocols-smtp-imap/SKILL.md +263 -0
- package/skills/offensive/airecon-fork/protocols-snmp/SKILL.md +147 -0
- package/skills/offensive/airecon-fork/protocols-ssh/SKILL.md +287 -0
- package/skills/offensive/airecon-fork/reconnaissance-asn-whois-osint/SKILL.md +236 -0
- package/skills/offensive/airecon-fork/reconnaissance-ctf-methodology/SKILL.md +435 -0
- package/skills/offensive/airecon-fork/reconnaissance-dorking/SKILL.md +182 -0
- package/skills/offensive/airecon-fork/reconnaissance-exposed-devtools-detection/SKILL.md +513 -0
- package/skills/offensive/airecon-fork/reconnaissance-full-recon/SKILL.md +305 -0
- package/skills/offensive/airecon-fork/reconnaissance-internal-pentest/SKILL.md +202 -0
- package/skills/offensive/airecon-fork/reconnaissance-javascript-analysis/SKILL.md +167 -0
- package/skills/offensive/airecon-fork/reconnaissance-js-internal-hostname-intelligence/SKILL.md +391 -0
- package/skills/offensive/airecon-fork/reconnaissance-monitoring-secrets-exposure/SKILL.md +394 -0
- package/skills/offensive/airecon-fork/reconnaissance-shodan-censys/SKILL.md +279 -0
- package/skills/offensive/airecon-fork/reconnaissance-subdomain-enum/SKILL.md +952 -0
- package/skills/offensive/airecon-fork/technologies-cicd-attacks/SKILL.md +283 -0
- package/skills/offensive/airecon-fork/technologies-cloud-security/SKILL.md +299 -0
- package/skills/offensive/airecon-fork/technologies-docker-container/SKILL.md +266 -0
- package/skills/offensive/airecon-fork/technologies-elasticsearch/SKILL.md +226 -0
- package/skills/offensive/airecon-fork/technologies-firebase-firestore/SKILL.md +213 -0
- package/skills/offensive/airecon-fork/technologies-frida-hooking/SKILL.md +387 -0
- package/skills/offensive/airecon-fork/technologies-gitlab-github/SKILL.md +259 -0
- package/skills/offensive/airecon-fork/technologies-jenkins/SKILL.md +256 -0
- package/skills/offensive/airecon-fork/technologies-kubernetes-pentest/SKILL.md +281 -0
- package/skills/offensive/airecon-fork/technologies-memcached/SKILL.md +230 -0
- package/skills/offensive/airecon-fork/technologies-mobile-app-pentesting/SKILL.md +105 -0
- package/skills/offensive/airecon-fork/technologies-mongodb/SKILL.md +257 -0
- package/skills/offensive/airecon-fork/technologies-nginx-apache/SKILL.md +280 -0
- package/skills/offensive/airecon-fork/technologies-observability-stack-attacks/SKILL.md +501 -0
- package/skills/offensive/airecon-fork/technologies-redis/SKILL.md +236 -0
- package/skills/offensive/airecon-fork/technologies-supabase/SKILL.md +270 -0
- package/skills/offensive/airecon-fork/technologies-tomcat/SKILL.md +232 -0
- package/skills/offensive/airecon-fork/tools-advanced-fuzzing/SKILL.md +351 -0
- package/skills/offensive/airecon-fork/tools-browser-automation/SKILL.md +300 -0
- package/skills/offensive/airecon-fork/tools-caido/SKILL.md +776 -0
- package/skills/offensive/airecon-fork/tools-code-review/SKILL.md +71 -0
- package/skills/offensive/airecon-fork/tools-dalfox/SKILL.md +189 -0
- package/skills/offensive/airecon-fork/tools-hashcat-john/SKILL.md +258 -0
- package/skills/offensive/airecon-fork/tools-impacket/SKILL.md +227 -0
- package/skills/offensive/airecon-fork/tools-install/SKILL.md +202 -0
- package/skills/offensive/airecon-fork/tools-metasploit/SKILL.md +270 -0
- package/skills/offensive/airecon-fork/tools-nmap/SKILL.md +211 -0
- package/skills/offensive/airecon-fork/tools-nuclei/SKILL.md +175 -0
- package/skills/offensive/airecon-fork/tools-reporting/SKILL.md +47 -0
- package/skills/offensive/airecon-fork/tools-scripting/SKILL.md +1939 -0
- package/skills/offensive/airecon-fork/tools-semgrep/SKILL.md +202 -0
- package/skills/offensive/airecon-fork/tools-source-audit/SKILL.md +308 -0
- package/skills/offensive/airecon-fork/tools-sqlmap/SKILL.md +137 -0
- package/skills/offensive/airecon-fork/tools-tool-catalog/SKILL.md +320 -0
- package/skills/offensive/airecon-fork/tools-wapiti/SKILL.md +293 -0
- package/skills/offensive/airecon-fork/vulnerabilities-2fa-bypass/SKILL.md +219 -0
- package/skills/offensive/airecon-fork/vulnerabilities-account-takeover/SKILL.md +223 -0
- package/skills/offensive/airecon-fork/vulnerabilities-api-schema-exposure/SKILL.md +849 -0
- package/skills/offensive/airecon-fork/vulnerabilities-api-testing/SKILL.md +278 -0
- package/skills/offensive/airecon-fork/vulnerabilities-auth-workflow/SKILL.md +252 -0
- package/skills/offensive/airecon-fork/vulnerabilities-authentication-jwt/SKILL.md +158 -0
- package/skills/offensive/airecon-fork/vulnerabilities-bfla/SKILL.md +156 -0
- package/skills/offensive/airecon-fork/vulnerabilities-blind-xss/SKILL.md +111 -0
- package/skills/offensive/airecon-fork/vulnerabilities-business-logic/SKILL.md +313 -0
- package/skills/offensive/airecon-fork/vulnerabilities-cors/SKILL.md +242 -0
- package/skills/offensive/airecon-fork/vulnerabilities-crlf-injection/SKILL.md +146 -0
- package/skills/offensive/airecon-fork/vulnerabilities-csrf/SKILL.md +200 -0
- package/skills/offensive/airecon-fork/vulnerabilities-csrf-advanced-bypass/SKILL.md +536 -0
- package/skills/offensive/airecon-fork/vulnerabilities-deserialization/SKILL.md +363 -0
- package/skills/offensive/airecon-fork/vulnerabilities-dom-based-vulnerabilities/SKILL.md +105 -0
- package/skills/offensive/airecon-fork/vulnerabilities-exploitation/SKILL.md +286 -0
- package/skills/offensive/airecon-fork/vulnerabilities-grpc/SKILL.md +123 -0
- package/skills/offensive/airecon-fork/vulnerabilities-host-header-injection/SKILL.md +169 -0
- package/skills/offensive/airecon-fork/vulnerabilities-http-smuggling/SKILL.md +411 -0
- package/skills/offensive/airecon-fork/vulnerabilities-idor/SKILL.md +705 -0
- package/skills/offensive/airecon-fork/vulnerabilities-information-disclosure/SKILL.md +867 -0
- package/skills/offensive/airecon-fork/vulnerabilities-insecure-file-uploads/SKILL.md +190 -0
- package/skills/offensive/airecon-fork/vulnerabilities-jwt-attacks/SKILL.md +270 -0
- package/skills/offensive/airecon-fork/vulnerabilities-kubernetes/SKILL.md +252 -0
- package/skills/offensive/airecon-fork/vulnerabilities-mass-assignment/SKILL.md +788 -0
- package/skills/offensive/airecon-fork/vulnerabilities-nosql-injection/SKILL.md +204 -0
- package/skills/offensive/airecon-fork/vulnerabilities-oauth-misconfig/SKILL.md +220 -0
- package/skills/offensive/airecon-fork/vulnerabilities-oauth-saml/SKILL.md +163 -0
- package/skills/offensive/airecon-fork/vulnerabilities-open-redirect/SKILL.md +167 -0
- package/skills/offensive/airecon-fork/vulnerabilities-password-reset-poisoning/SKILL.md +66 -0
- package/skills/offensive/airecon-fork/vulnerabilities-path-traversal/SKILL.md +192 -0
- package/skills/offensive/airecon-fork/vulnerabilities-privilege-escalation/SKILL.md +320 -0
- package/skills/offensive/airecon-fork/vulnerabilities-prototype-pollution/SKILL.md +242 -0
- package/skills/offensive/airecon-fork/vulnerabilities-race-conditions/SKILL.md +192 -0
- package/skills/offensive/airecon-fork/vulnerabilities-rce/SKILL.md +240 -0
- package/skills/offensive/airecon-fork/vulnerabilities-sensitive-file-pii-exposure/SKILL.md +589 -0
- package/skills/offensive/airecon-fork/vulnerabilities-spring4shell/SKILL.md +86 -0
- package/skills/offensive/airecon-fork/vulnerabilities-sql-injection/SKILL.md +313 -0
- package/skills/offensive/airecon-fork/vulnerabilities-ssrf/SKILL.md +183 -0
- package/skills/offensive/airecon-fork/vulnerabilities-ssti/SKILL.md +344 -0
- package/skills/offensive/airecon-fork/vulnerabilities-subdomain-takeover/SKILL.md +160 -0
- package/skills/offensive/airecon-fork/vulnerabilities-supply-chain/SKILL.md +125 -0
- package/skills/offensive/airecon-fork/vulnerabilities-unhandled-exception-differential/SKILL.md +742 -0
- package/skills/offensive/airecon-fork/vulnerabilities-waf-detection/SKILL.md +90 -0
- package/skills/offensive/airecon-fork/vulnerabilities-web-cache-poisoning/SKILL.md +233 -0
- package/skills/offensive/airecon-fork/vulnerabilities-websocket/SKILL.md +180 -0
- package/skills/offensive/airecon-fork/vulnerabilities-xss/SKILL.md +316 -0
- package/skills/offensive/airecon-fork/vulnerabilities-xxe/SKILL.md +222 -0
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
<!-- aegis-local: forked 2026-05-04 from pikpikcu/airecon@9a21453459d87eefb012ea355c79b593d0d3c0cc (MIT-licensed); attribution preserved, see ATTRIBUTION.md -->
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
name: api-schema-exposure
|
|
5
|
+
description: Public OpenAPI/Swagger specification exposure - detection, deep content analysis, internal hostname extraction, endpoint inventory, and attack chain building
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# API Schema Exposure (OpenAPI / Swagger / Redoc)
|
|
9
|
+
|
|
10
|
+
Publicly accessible API documentation (OpenAPI, Swagger, Redoc) reveals the full attack surface of an API to unauthenticated attackers: endpoint inventory, parameter names, authentication schemes, internal server hostnames, and error response shapes. Even when endpoints enforce auth, the spec eliminates all reconnaissance effort.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Why This Matters
|
|
15
|
+
|
|
16
|
+
A typical API doc exposure provides:
|
|
17
|
+
1. **Internal hostnames** in `servers[]` → SSRF pivot, internal network mapping
|
|
18
|
+
2. **Full endpoint inventory** → skip discovery entirely, jump to exploitation
|
|
19
|
+
3. **Auth scheme details** → exact header names, token formats, security flows
|
|
20
|
+
4. **Parameter names/types** → craft precise injection payloads without guessing
|
|
21
|
+
5. **Unauthenticated endpoints** → paths with `security: []` are public by design — test for abuse
|
|
22
|
+
6. **Error/response shapes** → differential oracle for blind attacks
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Detection: All API Doc Paths
|
|
27
|
+
|
|
28
|
+
Framework-specific default documentation paths:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
API_DOC_PATHS = [
|
|
32
|
+
# Generic / framework-agnostic
|
|
33
|
+
"/docs", "/docs/", "/docs.json", "/docs.html", "/docs.yaml",
|
|
34
|
+
"/doc", "/doc/", "/doc.json",
|
|
35
|
+
"/swagger", "/swagger/", "/swagger.json", "/swagger.yaml",
|
|
36
|
+
"/swagger-ui", "/swagger-ui.html", "/swagger-ui/index.html",
|
|
37
|
+
"/swagger/index.html",
|
|
38
|
+
"/api-docs", "/api-docs/", "/api-docs.json", "/api-docs.yaml",
|
|
39
|
+
"/api/docs", "/api/docs.json", "/api/swagger.json",
|
|
40
|
+
"/openapi", "/openapi.json", "/openapi.yaml",
|
|
41
|
+
"/openapi/v1", "/openapi/v2", "/openapi/v3",
|
|
42
|
+
"/redoc", "/redoc/", "/redoc.html",
|
|
43
|
+
"/reference", "/reference.json",
|
|
44
|
+
|
|
45
|
+
# Version-prefixed
|
|
46
|
+
"/v1/docs", "/v1/docs.json", "/v1/swagger.json", "/v1/openapi.json", "/v1/api-docs",
|
|
47
|
+
"/v2/docs", "/v2/docs.json", "/v2/swagger.json", "/v2/openapi.json", "/v2/api-docs",
|
|
48
|
+
"/v3/docs", "/v3/docs.json", "/v3/swagger.json", "/v3/openapi.json", "/v3/api-docs",
|
|
49
|
+
"/api/v1/docs", "/api/v1/swagger.json", "/api/v1/openapi.json",
|
|
50
|
+
"/api/v2/docs", "/api/v2/swagger.json",
|
|
51
|
+
"/api/v3/docs", "/api/v3/swagger.json",
|
|
52
|
+
|
|
53
|
+
# Framework-specific defaults
|
|
54
|
+
# NestJS → /docs, /docs.json, /docs.html, /api, /api-json
|
|
55
|
+
"/api", "/api/", "/api-json",
|
|
56
|
+
# Fastify (swagger plugin) → /documentation, /documentation/json, /documentation/yaml
|
|
57
|
+
"/documentation", "/documentation/json", "/documentation/yaml",
|
|
58
|
+
"/documentation/static/index.html",
|
|
59
|
+
# Spring Boot (springdoc-openapi) → /v3/api-docs, /swagger-ui.html
|
|
60
|
+
"/v3/api-docs", "/v3/api-docs.yaml",
|
|
61
|
+
"/v3/api-docs/swagger-config",
|
|
62
|
+
"/actuator/openapi",
|
|
63
|
+
# FastAPI → /docs, /redoc, /openapi.json
|
|
64
|
+
# Flask-RESTx / Flasgger → /apispec.json, /apispec_1.json
|
|
65
|
+
"/apispec.json", "/apispec_1.json",
|
|
66
|
+
# Django REST Framework → /schema/, /schema.json, /schema.yaml
|
|
67
|
+
"/schema/", "/schema.json", "/schema.yaml",
|
|
68
|
+
# Hapi.js (hapi-swagger) → /documentation
|
|
69
|
+
# Go (swaggo) → /swagger/doc.json
|
|
70
|
+
"/swagger/doc.json",
|
|
71
|
+
# Laravel (l5-swagger) → /api/documentation
|
|
72
|
+
"/api/documentation",
|
|
73
|
+
# Ruby on Rails (rswag) → /api-docs/v1, /api-docs/v2
|
|
74
|
+
"/api-docs/v1", "/api-docs/v2",
|
|
75
|
+
# .NET → /swagger/v1/swagger.json, /swagger/v2/swagger.json
|
|
76
|
+
"/swagger/v1/swagger.json", "/swagger/v2/swagger.json",
|
|
77
|
+
"/swagger/v1/swagger.yaml",
|
|
78
|
+
# Express (express-openapi) → /api-doc
|
|
79
|
+
"/api-doc",
|
|
80
|
+
# Pydantic/FastAPI alternatives
|
|
81
|
+
"/openapi.json", "/openapi.yaml",
|
|
82
|
+
# Admin and internal variants
|
|
83
|
+
"/internal/docs", "/internal/swagger",
|
|
84
|
+
"/admin/docs", "/admin/swagger", "/admin/openapi.json",
|
|
85
|
+
"/private/docs", "/private/openapi.json",
|
|
86
|
+
"/_docs", "/_swagger",
|
|
87
|
+
]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Script 1 — API Doc Scanner
|
|
93
|
+
|
|
94
|
+
Scans all known paths and finds accessible API documentation endpoints.
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
#!/usr/bin/env python3
|
|
98
|
+
"""
|
|
99
|
+
API documentation endpoint scanner.
|
|
100
|
+
Finds exposed OpenAPI/Swagger specs across all framework-specific paths.
|
|
101
|
+
|
|
102
|
+
Usage: python3 api_doc_scan.py --url https://api.target.com [--threads 30]
|
|
103
|
+
python3 api_doc_scan.py --hosts live_hosts.txt [--threads 30]
|
|
104
|
+
"""
|
|
105
|
+
import ssl, json, argparse
|
|
106
|
+
from urllib.request import urlopen, Request
|
|
107
|
+
from urllib.error import HTTPError, URLError
|
|
108
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
109
|
+
|
|
110
|
+
ctx = ssl.create_default_context()
|
|
111
|
+
ctx.check_hostname = False
|
|
112
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
113
|
+
|
|
114
|
+
UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
|
|
115
|
+
|
|
116
|
+
API_DOC_PATHS = [
|
|
117
|
+
"/docs", "/docs.json", "/docs.html", "/docs.yaml",
|
|
118
|
+
"/doc.json", "/doc",
|
|
119
|
+
"/swagger", "/swagger.json", "/swagger.yaml", "/swagger-ui.html",
|
|
120
|
+
"/swagger-ui/index.html", "/swagger/index.html",
|
|
121
|
+
"/api-docs", "/api-docs.json", "/api-docs.yaml",
|
|
122
|
+
"/api/docs", "/api/docs.json", "/api/swagger.json",
|
|
123
|
+
"/openapi.json", "/openapi.yaml",
|
|
124
|
+
"/redoc", "/redoc.html",
|
|
125
|
+
"/v1/api-docs", "/v2/api-docs", "/v3/api-docs",
|
|
126
|
+
"/v3/api-docs", "/v3/api-docs.yaml",
|
|
127
|
+
"/v1/swagger.json", "/v2/swagger.json", "/v3/swagger.json",
|
|
128
|
+
"/documentation", "/documentation/json", "/documentation/yaml",
|
|
129
|
+
"/apispec.json", "/apispec_1.json",
|
|
130
|
+
"/schema.json", "/schema.yaml",
|
|
131
|
+
"/swagger/doc.json",
|
|
132
|
+
"/api/documentation",
|
|
133
|
+
"/api-docs/v1", "/api-docs/v2",
|
|
134
|
+
"/swagger/v1/swagger.json", "/swagger/v2/swagger.json",
|
|
135
|
+
"/api-doc",
|
|
136
|
+
"/api-json",
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
OPENAPI_SIGNALS = ["openapi", "swagger", "paths", "components", "info", "servers"]
|
|
140
|
+
HTML_SIGNALS = ["swagger-ui", "redoc", "openapi", "ReDoc", "API Documentation"]
|
|
141
|
+
|
|
142
|
+
def is_api_spec(body_bytes, content_type):
|
|
143
|
+
"""Returns True if response looks like an OpenAPI spec or UI."""
|
|
144
|
+
try:
|
|
145
|
+
text = body_bytes[:2000].decode(errors='replace').lower()
|
|
146
|
+
except Exception:
|
|
147
|
+
return False
|
|
148
|
+
if "json" in (content_type or "") or "yaml" in (content_type or ""):
|
|
149
|
+
return any(sig in text for sig in ["openapi", "swagger", '"paths"', '"info"'])
|
|
150
|
+
if "html" in (content_type or ""):
|
|
151
|
+
return any(sig.lower() in text for sig in HTML_SIGNALS)
|
|
152
|
+
return any(sig in text for sig in OPENAPI_SIGNALS)
|
|
153
|
+
|
|
154
|
+
def check_path(base, path):
|
|
155
|
+
url = base.rstrip("/") + path
|
|
156
|
+
try:
|
|
157
|
+
req = Request(url, headers={"User-Agent": UA, "Accept": "application/json, text/html, */*"})
|
|
158
|
+
resp = urlopen(req, context=ctx, timeout=8)
|
|
159
|
+
body = resp.read()
|
|
160
|
+
ct = resp.headers.get("Content-Type", "")
|
|
161
|
+
if resp.status == 200 and len(body) > 200 and is_api_spec(body, ct):
|
|
162
|
+
return {
|
|
163
|
+
"url": url,
|
|
164
|
+
"path": path,
|
|
165
|
+
"status": resp.status,
|
|
166
|
+
"size": len(body),
|
|
167
|
+
"content_type": ct,
|
|
168
|
+
"body": body
|
|
169
|
+
}
|
|
170
|
+
except HTTPError:
|
|
171
|
+
pass
|
|
172
|
+
except URLError:
|
|
173
|
+
pass
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
def scan_host(base, paths, max_workers=30):
|
|
177
|
+
results = []
|
|
178
|
+
with ThreadPoolExecutor(max_workers=max_workers) as ex:
|
|
179
|
+
futs = {ex.submit(check_path, base, p): p for p in paths}
|
|
180
|
+
for fut in as_completed(futs):
|
|
181
|
+
r = fut.result()
|
|
182
|
+
if r:
|
|
183
|
+
results.append(r)
|
|
184
|
+
return results
|
|
185
|
+
|
|
186
|
+
parser = argparse.ArgumentParser()
|
|
187
|
+
parser.add_argument("--url", help="Single target base URL")
|
|
188
|
+
parser.add_argument("--hosts", help="File with host URLs")
|
|
189
|
+
parser.add_argument("--threads", type=int, default=30)
|
|
190
|
+
parser.add_argument("--save-specs", action="store_true", help="Save raw spec bodies to disk")
|
|
191
|
+
args = parser.parse_args()
|
|
192
|
+
|
|
193
|
+
targets = []
|
|
194
|
+
if args.url:
|
|
195
|
+
targets.append(args.url)
|
|
196
|
+
if args.hosts:
|
|
197
|
+
targets += [l.strip() for l in open(args.hosts) if l.strip()]
|
|
198
|
+
|
|
199
|
+
all_found = []
|
|
200
|
+
for target in targets:
|
|
201
|
+
print(f"[*] Scanning {target} ({len(API_DOC_PATHS)} paths)")
|
|
202
|
+
found = scan_host(target, API_DOC_PATHS, args.threads)
|
|
203
|
+
for r in found:
|
|
204
|
+
print(f" [FOUND] {r['url']} → HTTP {r['status']} ({r['size']}B) {r['content_type']}")
|
|
205
|
+
if args.save_specs:
|
|
206
|
+
fname = r['url'].replace('https://', '').replace('http://', '').replace('/', '_') + ".json"
|
|
207
|
+
open(fname, 'wb').write(r['body'])
|
|
208
|
+
print(f" Saved: {fname}")
|
|
209
|
+
all_found.append(r)
|
|
210
|
+
|
|
211
|
+
print(f"\n[*] Total specs found: {len(all_found)}")
|
|
212
|
+
for r in all_found:
|
|
213
|
+
print(f" {r['url']}")
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Script 2 — OpenAPI Spec Deep Analyzer
|
|
219
|
+
|
|
220
|
+
Parses a found spec and extracts all intelligence: internal hostnames, security schemes, unauthenticated endpoints, sensitive paths.
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
#!/usr/bin/env python3
|
|
224
|
+
"""
|
|
225
|
+
OpenAPI spec deep analyzer.
|
|
226
|
+
Extracts: internal hostnames, security schemes, unauthenticated endpoints,
|
|
227
|
+
sensitive paths, parameter inventory, response shapes.
|
|
228
|
+
|
|
229
|
+
Usage: python3 openapi_analyze.py --url https://api.target.com/docs.json
|
|
230
|
+
python3 openapi_analyze.py --file spec.json
|
|
231
|
+
"""
|
|
232
|
+
import ssl, json, re, argparse
|
|
233
|
+
from urllib.request import urlopen, Request
|
|
234
|
+
from urllib.error import HTTPError
|
|
235
|
+
from urllib.parse import urlparse
|
|
236
|
+
|
|
237
|
+
ctx = ssl.create_default_context()
|
|
238
|
+
ctx.check_hostname = False
|
|
239
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
240
|
+
|
|
241
|
+
UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
|
|
242
|
+
|
|
243
|
+
INTERNAL_HOST_PATTERNS = [
|
|
244
|
+
r'https?://[a-z0-9\-]+\.internal\.[a-z0-9\-\.]+', # *.internal.*
|
|
245
|
+
r'https?://[a-z0-9\-]+\.(?:internal|local|corp|lan|intra|private|priv)', # TLD
|
|
246
|
+
r'https?://(?:10|172|192\.168)\.[0-9.]+', # RFC1918 IP
|
|
247
|
+
r'https?://localhost[:/]', # Localhost
|
|
248
|
+
r'https?://[a-z0-9\-]+-(?:internal|int|priv|private)\.', # suffix pattern
|
|
249
|
+
r'https?://(?:dev|stg|staging|uat|ppd|preprod)\.[a-z0-9\-\.]+', # Env subdomains
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
SENSITIVE_PATH_KEYWORDS = [
|
|
253
|
+
"admin", "internal", "debug", "private", "secret", "management",
|
|
254
|
+
"impersonate", "sudo", "superuser", "system", "audit", "config",
|
|
255
|
+
"backup", "export", "migrate", "reset", "revoke", "purge",
|
|
256
|
+
]
|
|
257
|
+
|
|
258
|
+
SENSITIVE_PARAM_KEYWORDS = [
|
|
259
|
+
"password", "secret", "token", "key", "credential", "auth",
|
|
260
|
+
"ssn", "tax", "credit_card", "card_number", "cvv",
|
|
261
|
+
"admin", "role", "permission", "scope",
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
def fetch_spec(url):
|
|
265
|
+
try:
|
|
266
|
+
req = Request(url, headers={"User-Agent": UA, "Accept": "application/json"})
|
|
267
|
+
resp = urlopen(req, context=ctx, timeout=20)
|
|
268
|
+
return json.loads(resp.read())
|
|
269
|
+
except Exception as e:
|
|
270
|
+
print(f"[-] Failed to fetch spec: {e}")
|
|
271
|
+
return None
|
|
272
|
+
|
|
273
|
+
def analyze_spec(spec, source_url=None):
|
|
274
|
+
report = {
|
|
275
|
+
"meta": {},
|
|
276
|
+
"internal_hostnames": [],
|
|
277
|
+
"security_schemes": {},
|
|
278
|
+
"unauthenticated_endpoints": [],
|
|
279
|
+
"sensitive_endpoints": [],
|
|
280
|
+
"all_endpoints": [],
|
|
281
|
+
"sensitive_params": [],
|
|
282
|
+
"total_paths": 0,
|
|
283
|
+
"total_operations": 0,
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
# ── 1. Metadata ────────────────────────────────────────────
|
|
287
|
+
info = spec.get("info", {})
|
|
288
|
+
report["meta"] = {
|
|
289
|
+
"title": info.get("title"),
|
|
290
|
+
"version": info.get("version"),
|
|
291
|
+
"openapi": spec.get("openapi") or spec.get("swagger"),
|
|
292
|
+
"description": (info.get("description") or "")[:200],
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
# ── 2. Internal hostnames in servers[] ─────────────────────
|
|
296
|
+
servers = spec.get("servers", [])
|
|
297
|
+
if isinstance(servers, list):
|
|
298
|
+
for srv in servers:
|
|
299
|
+
url = srv.get("url", "")
|
|
300
|
+
for pat in INTERNAL_HOST_PATTERNS:
|
|
301
|
+
if re.search(pat, url, re.IGNORECASE):
|
|
302
|
+
report["internal_hostnames"].append({
|
|
303
|
+
"url": url,
|
|
304
|
+
"pattern": pat,
|
|
305
|
+
"description": srv.get("description", "")
|
|
306
|
+
})
|
|
307
|
+
break
|
|
308
|
+
# Swagger 2.0 style: host + basePath
|
|
309
|
+
if "host" in spec:
|
|
310
|
+
host = spec["host"]
|
|
311
|
+
base = spec.get("basePath", "")
|
|
312
|
+
for pat in INTERNAL_HOST_PATTERNS:
|
|
313
|
+
if re.search(pat, host, re.IGNORECASE):
|
|
314
|
+
report["internal_hostnames"].append({"url": f"https://{host}{base}", "pattern": pat})
|
|
315
|
+
|
|
316
|
+
# ── 3. Security schemes ────────────────────────────────────
|
|
317
|
+
components = spec.get("components", spec.get("securityDefinitions", {}))
|
|
318
|
+
sec_schemes = components.get("securitySchemes", components) if "securitySchemes" in components else spec.get("securityDefinitions", {})
|
|
319
|
+
for name, scheme in (sec_schemes or {}).items():
|
|
320
|
+
report["security_schemes"][name] = {
|
|
321
|
+
"type": scheme.get("type"),
|
|
322
|
+
"in": scheme.get("in"), # header, query, cookie
|
|
323
|
+
"name": scheme.get("name"), # Header/param name
|
|
324
|
+
"scheme": scheme.get("scheme"), # bearer, basic
|
|
325
|
+
"flows": list(scheme.get("flows", {}).keys()) if "flows" in scheme else None,
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
# ── 4. Global security requirement ─────────────────────────
|
|
329
|
+
global_security = spec.get("security", None)
|
|
330
|
+
global_unauth = (global_security == [] or global_security == [{}])
|
|
331
|
+
|
|
332
|
+
# ── 5. Enumerate all paths ─────────────────────────────────
|
|
333
|
+
paths = spec.get("paths", {})
|
|
334
|
+
report["total_paths"] = len(paths)
|
|
335
|
+
HTTP_METHODS = ["get", "post", "put", "patch", "delete", "options", "head"]
|
|
336
|
+
|
|
337
|
+
for path, path_item in paths.items():
|
|
338
|
+
for method in HTTP_METHODS:
|
|
339
|
+
op = path_item.get(method)
|
|
340
|
+
if not op:
|
|
341
|
+
continue
|
|
342
|
+
report["total_operations"] += 1
|
|
343
|
+
|
|
344
|
+
op_id = op.get("operationId", "")
|
|
345
|
+
summary = op.get("summary", "")
|
|
346
|
+
tags = op.get("tags", [])
|
|
347
|
+
|
|
348
|
+
# Per-operation security
|
|
349
|
+
op_security = op.get("security", None)
|
|
350
|
+
is_unauth = (op_security == [] or op_security == [{}]) or (op_security is None and global_unauth)
|
|
351
|
+
|
|
352
|
+
# Collect params
|
|
353
|
+
params = []
|
|
354
|
+
for p in (op.get("parameters") or []):
|
|
355
|
+
pname = p.get("name", "")
|
|
356
|
+
ploc = p.get("in", "")
|
|
357
|
+
params.append({"name": pname, "in": ploc})
|
|
358
|
+
if any(k in pname.lower() for k in SENSITIVE_PARAM_KEYWORDS):
|
|
359
|
+
report["sensitive_params"].append({
|
|
360
|
+
"path": path, "method": method.upper(),
|
|
361
|
+
"param": pname, "in": ploc
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
entry = {
|
|
365
|
+
"path": path,
|
|
366
|
+
"method": method.upper(),
|
|
367
|
+
"operationId": op_id,
|
|
368
|
+
"summary": summary,
|
|
369
|
+
"tags": tags,
|
|
370
|
+
"authenticated": not is_unauth,
|
|
371
|
+
"params": params,
|
|
372
|
+
}
|
|
373
|
+
report["all_endpoints"].append(entry)
|
|
374
|
+
|
|
375
|
+
if is_unauth:
|
|
376
|
+
report["unauthenticated_endpoints"].append(entry)
|
|
377
|
+
|
|
378
|
+
# Sensitive path detection
|
|
379
|
+
if any(k in path.lower() or k in op_id.lower() or k in summary.lower()
|
|
380
|
+
for k in SENSITIVE_PATH_KEYWORDS):
|
|
381
|
+
report["sensitive_endpoints"].append(entry)
|
|
382
|
+
|
|
383
|
+
return report
|
|
384
|
+
|
|
385
|
+
def print_report(report, source_url=None):
|
|
386
|
+
print(f"\n{'='*70}")
|
|
387
|
+
print(f"API SCHEMA EXPOSURE ANALYSIS")
|
|
388
|
+
if source_url:
|
|
389
|
+
print(f"Source: {source_url}")
|
|
390
|
+
print(f"{'='*70}")
|
|
391
|
+
|
|
392
|
+
m = report["meta"]
|
|
393
|
+
print(f"\n[META]")
|
|
394
|
+
print(f" Title: {m.get('title')}")
|
|
395
|
+
print(f" Version: {m.get('version')}")
|
|
396
|
+
print(f" OpenAPI: {m.get('openapi')}")
|
|
397
|
+
print(f" Paths: {report['total_paths']} | Operations: {report['total_operations']}")
|
|
398
|
+
|
|
399
|
+
if report["internal_hostnames"]:
|
|
400
|
+
print(f"\n[INTERNAL HOSTNAMES EXPOSED] ← HIGH VALUE for SSRF/network mapping")
|
|
401
|
+
for h in report["internal_hostnames"]:
|
|
402
|
+
print(f" {h['url']}")
|
|
403
|
+
if h.get("description"):
|
|
404
|
+
print(f" Description: {h['description']}")
|
|
405
|
+
else:
|
|
406
|
+
print(f"\n[Hostnames] No internal hostnames detected in servers[]")
|
|
407
|
+
|
|
408
|
+
if report["security_schemes"]:
|
|
409
|
+
print(f"\n[SECURITY SCHEMES]")
|
|
410
|
+
for name, scheme in report["security_schemes"].items():
|
|
411
|
+
print(f" {name}:")
|
|
412
|
+
print(f" Type: {scheme['type']} | In: {scheme['in']} | Name/Header: {scheme['name']}")
|
|
413
|
+
if scheme.get("scheme"):
|
|
414
|
+
print(f" Scheme: {scheme['scheme']}")
|
|
415
|
+
if scheme.get("flows"):
|
|
416
|
+
print(f" OAuth Flows: {scheme['flows']}")
|
|
417
|
+
|
|
418
|
+
if report["unauthenticated_endpoints"]:
|
|
419
|
+
print(f"\n[UNAUTHENTICATED ENDPOINTS] ({len(report['unauthenticated_endpoints'])}) ← Test for abuse/enumeration")
|
|
420
|
+
for ep in report["unauthenticated_endpoints"][:20]:
|
|
421
|
+
params = ", ".join([p['name'] for p in ep['params']]) if ep['params'] else "(no params)"
|
|
422
|
+
print(f" {ep['method']:6} {ep['path']} [{params}]")
|
|
423
|
+
else:
|
|
424
|
+
print(f"\n[Unauthenticated Endpoints] All endpoints require auth (per spec)")
|
|
425
|
+
|
|
426
|
+
if report["sensitive_endpoints"]:
|
|
427
|
+
print(f"\n[SENSITIVE ENDPOINTS] ({len(report['sensitive_endpoints'])}) ← Priority targets")
|
|
428
|
+
for ep in report["sensitive_endpoints"][:20]:
|
|
429
|
+
auth_flag = "AUTH" if ep['authenticated'] else "NO-AUTH"
|
|
430
|
+
print(f" [{auth_flag}] {ep['method']:6} {ep['path']} ({ep.get('summary','')[:60]})")
|
|
431
|
+
|
|
432
|
+
if report["sensitive_params"]:
|
|
433
|
+
print(f"\n[SENSITIVE PARAMETERS] ({len(report['sensitive_params'])})")
|
|
434
|
+
for p in report["sensitive_params"][:15]:
|
|
435
|
+
print(f" {p['method']} {p['path']} — param '{p['param']}' in {p['in']}")
|
|
436
|
+
|
|
437
|
+
print(f"\n[SAMPLE ENDPOINTS] (first 15 of {report['total_paths']})")
|
|
438
|
+
for ep in report["all_endpoints"][:15]:
|
|
439
|
+
auth_flag = "✓" if ep['authenticated'] else "✗UNAUTH"
|
|
440
|
+
print(f" [{auth_flag}] {ep['method']:6} {ep['path']}")
|
|
441
|
+
|
|
442
|
+
parser = argparse.ArgumentParser()
|
|
443
|
+
parser.add_argument("--url", help="URL of the spec (e.g. https://api.target.com/docs.json)")
|
|
444
|
+
parser.add_argument("--file", help="Local spec file path")
|
|
445
|
+
parser.add_argument("--out", help="Save full report as JSON")
|
|
446
|
+
args = parser.parse_args()
|
|
447
|
+
|
|
448
|
+
if args.url:
|
|
449
|
+
print(f"[*] Fetching spec from {args.url}")
|
|
450
|
+
spec = fetch_spec(args.url)
|
|
451
|
+
source = args.url
|
|
452
|
+
elif args.file:
|
|
453
|
+
with open(args.file) as f:
|
|
454
|
+
spec = json.load(f)
|
|
455
|
+
source = args.file
|
|
456
|
+
else:
|
|
457
|
+
print("Specify --url or --file")
|
|
458
|
+
exit(1)
|
|
459
|
+
|
|
460
|
+
if spec:
|
|
461
|
+
report = analyze_spec(spec, source)
|
|
462
|
+
print_report(report, source)
|
|
463
|
+
if args.out:
|
|
464
|
+
with open(args.out, "w") as f:
|
|
465
|
+
json.dump(report, f, indent=2)
|
|
466
|
+
print(f"\n[*] Full report saved: {args.out}")
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Script 3 — Multi-Host API Doc Hunter
|
|
472
|
+
|
|
473
|
+
Scans all live hosts for exposed API docs in a single pass — designed for mass reconnaissance.
|
|
474
|
+
|
|
475
|
+
```python
|
|
476
|
+
#!/usr/bin/env python3
|
|
477
|
+
"""
|
|
478
|
+
Mass API doc scanner + internal hostname extractor.
|
|
479
|
+
Takes a list of hosts and finds all exposed OpenAPI specs.
|
|
480
|
+
For each found spec, immediately extracts internal hostnames.
|
|
481
|
+
|
|
482
|
+
Usage: python3 mass_api_doc_hunt.py -f live_hosts.txt [--analyze]
|
|
483
|
+
"""
|
|
484
|
+
import ssl, json, re, argparse
|
|
485
|
+
from urllib.request import urlopen, Request
|
|
486
|
+
from urllib.error import HTTPError, URLError
|
|
487
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
488
|
+
|
|
489
|
+
ctx = ssl.create_default_context()
|
|
490
|
+
ctx.check_hostname = False
|
|
491
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
492
|
+
|
|
493
|
+
UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
|
|
494
|
+
|
|
495
|
+
# High-priority paths to check first (fastest hits)
|
|
496
|
+
PRIORITY_PATHS = [
|
|
497
|
+
"/docs.json", "/openapi.json", "/swagger.json",
|
|
498
|
+
"/v3/api-docs", "/api-docs.json", "/api-docs",
|
|
499
|
+
"/docs", "/swagger-ui.html", "/redoc",
|
|
500
|
+
"/documentation/json", "/swagger/doc.json",
|
|
501
|
+
"/v1/api-docs", "/v2/api-docs",
|
|
502
|
+
"/api/swagger.json", "/api/openapi.json",
|
|
503
|
+
"/swagger/v1/swagger.json",
|
|
504
|
+
"/apispec.json", "/schema.json",
|
|
505
|
+
]
|
|
506
|
+
|
|
507
|
+
INTERNAL_PATTERNS = [
|
|
508
|
+
re.compile(r'https?://[a-z0-9\-]+\.internal\.[a-z0-9\-\.]+', re.I),
|
|
509
|
+
re.compile(r'https?://[a-z0-9\-]+\.(?:internal|local|corp|lan|intra|priv)', re.I),
|
|
510
|
+
re.compile(r'https?://(?:10|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\.\d+\.\d+', re.I),
|
|
511
|
+
]
|
|
512
|
+
|
|
513
|
+
def looks_like_spec(body_bytes):
|
|
514
|
+
try:
|
|
515
|
+
text = body_bytes[:500].decode(errors='replace')
|
|
516
|
+
return any(x in text for x in ['"openapi"', '"swagger"', '"paths"', '"info":{'])
|
|
517
|
+
except Exception:
|
|
518
|
+
return False
|
|
519
|
+
|
|
520
|
+
def find_internal_hosts_fast(body_bytes):
|
|
521
|
+
try:
|
|
522
|
+
text = body_bytes.decode(errors='replace')
|
|
523
|
+
except Exception:
|
|
524
|
+
return []
|
|
525
|
+
found = []
|
|
526
|
+
for pat in INTERNAL_PATTERNS:
|
|
527
|
+
found.extend(pat.findall(text))
|
|
528
|
+
return list(set(found))
|
|
529
|
+
|
|
530
|
+
def check(base, path):
|
|
531
|
+
url = base.rstrip("/") + path
|
|
532
|
+
try:
|
|
533
|
+
req = Request(url, headers={"User-Agent": UA, "Accept": "application/json, */*"})
|
|
534
|
+
resp = urlopen(req, context=ctx, timeout=7)
|
|
535
|
+
body = resp.read()
|
|
536
|
+
if resp.status == 200 and len(body) > 300 and looks_like_spec(body):
|
|
537
|
+
internals = find_internal_hosts_fast(body)
|
|
538
|
+
try:
|
|
539
|
+
spec = json.loads(body)
|
|
540
|
+
path_count = len(spec.get("paths", {}))
|
|
541
|
+
title = spec.get("info", {}).get("title", "Unknown")
|
|
542
|
+
except Exception:
|
|
543
|
+
path_count = 0
|
|
544
|
+
title = "Unknown (YAML?)"
|
|
545
|
+
return {
|
|
546
|
+
"base": base, "path": path, "url": url,
|
|
547
|
+
"size": len(body), "title": title,
|
|
548
|
+
"path_count": path_count,
|
|
549
|
+
"internal_hosts": internals,
|
|
550
|
+
"body": body
|
|
551
|
+
}
|
|
552
|
+
except (HTTPError, URLError, Exception):
|
|
553
|
+
pass
|
|
554
|
+
return None
|
|
555
|
+
|
|
556
|
+
def scan_host(base):
|
|
557
|
+
for path in PRIORITY_PATHS:
|
|
558
|
+
result = check(base, path)
|
|
559
|
+
if result:
|
|
560
|
+
return result
|
|
561
|
+
return None
|
|
562
|
+
|
|
563
|
+
parser = argparse.ArgumentParser()
|
|
564
|
+
parser.add_argument("-f", "--file", required=True, help="File with live host URLs")
|
|
565
|
+
parser.add_argument("--threads", type=int, default=30)
|
|
566
|
+
parser.add_argument("--analyze", action="store_true", help="Run deep analysis on found specs")
|
|
567
|
+
args = parser.parse_args()
|
|
568
|
+
|
|
569
|
+
hosts = [l.strip() for l in open(args.file) if l.strip()]
|
|
570
|
+
print(f"[*] Scanning {len(hosts)} hosts for exposed API docs...")
|
|
571
|
+
|
|
572
|
+
findings = []
|
|
573
|
+
with ThreadPoolExecutor(max_workers=args.threads) as ex:
|
|
574
|
+
futs = {ex.submit(scan_host, h): h for h in hosts}
|
|
575
|
+
for fut in as_completed(futs):
|
|
576
|
+
r = fut.result()
|
|
577
|
+
if r:
|
|
578
|
+
findings.append(r)
|
|
579
|
+
print(f"\n[API SPEC FOUND] {r['url']}")
|
|
580
|
+
print(f" Title: {r['title']} | Paths: {r['path_count']} | Size: {r['size']}B")
|
|
581
|
+
if r["internal_hosts"]:
|
|
582
|
+
print(f" [INTERNAL HOSTS LEAKED]: {r['internal_hosts']}")
|
|
583
|
+
|
|
584
|
+
print(f"\n{'='*60}")
|
|
585
|
+
print(f"[*] Exposed specs found: {len(findings)}")
|
|
586
|
+
specs_with_internal = [f for f in findings if f["internal_hosts"]]
|
|
587
|
+
print(f"[*] With internal hostname disclosure: {len(specs_with_internal)}")
|
|
588
|
+
for f in specs_with_internal:
|
|
589
|
+
for h in f["internal_hosts"]:
|
|
590
|
+
print(f" {f['base']} → INTERNAL: {h}")
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
## Script 4 — Endpoint Inventory to Attack Matrix
|
|
596
|
+
|
|
597
|
+
Converts a discovered spec into a prioritized attack checklist.
|
|
598
|
+
|
|
599
|
+
```python
|
|
600
|
+
#!/usr/bin/env python3
|
|
601
|
+
"""
|
|
602
|
+
Convert OpenAPI spec to prioritized attack matrix.
|
|
603
|
+
Groups endpoints by risk and generates targeted test commands.
|
|
604
|
+
|
|
605
|
+
Usage: python3 spec_to_attack.py --url https://api.target.com/docs.json \
|
|
606
|
+
--token "Bearer <token>"
|
|
607
|
+
"""
|
|
608
|
+
import ssl, json, argparse, re
|
|
609
|
+
from urllib.request import urlopen, Request
|
|
610
|
+
from urllib.error import HTTPError
|
|
611
|
+
|
|
612
|
+
ctx = ssl.create_default_context()
|
|
613
|
+
ctx.check_hostname = False
|
|
614
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
615
|
+
UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
|
|
616
|
+
|
|
617
|
+
# Priority scoring for endpoints
|
|
618
|
+
def score_endpoint(path, method, op):
|
|
619
|
+
score = 0
|
|
620
|
+
reasons = []
|
|
621
|
+
path_l = path.lower()
|
|
622
|
+
op_str = json.dumps(op).lower()
|
|
623
|
+
|
|
624
|
+
# High-value path keywords
|
|
625
|
+
HIGH_KEYWORDS = ["admin", "user", "account", "billing", "invoice", "payment",
|
|
626
|
+
"export", "import", "upload", "download", "report", "key",
|
|
627
|
+
"token", "secret", "password", "reset", "impersonate", "role",
|
|
628
|
+
"permission", "config", "setting", "internal", "delete", "purge"]
|
|
629
|
+
for kw in HIGH_KEYWORDS:
|
|
630
|
+
if kw in path_l:
|
|
631
|
+
score += 2
|
|
632
|
+
reasons.append(f"path:{kw}")
|
|
633
|
+
|
|
634
|
+
# Methods that modify state
|
|
635
|
+
if method in ("POST", "PUT", "PATCH", "DELETE"):
|
|
636
|
+
score += 1
|
|
637
|
+
reasons.append(f"mutating:{method}")
|
|
638
|
+
|
|
639
|
+
# Has ID parameters (IDOR candidate)
|
|
640
|
+
if re.search(r'\{[a-z_]*id[a-z_]*\}', path, re.I):
|
|
641
|
+
score += 3
|
|
642
|
+
reasons.append("id-param:IDOR-candidate")
|
|
643
|
+
|
|
644
|
+
# Has multiple ID params (compound IDOR)
|
|
645
|
+
id_params = re.findall(r'\{([a-z_]*id[a-z_]*)\}', path, re.I)
|
|
646
|
+
if len(id_params) > 1:
|
|
647
|
+
score += 2
|
|
648
|
+
reasons.append(f"multi-id:{id_params}")
|
|
649
|
+
|
|
650
|
+
# Unauthenticated (security: [])
|
|
651
|
+
if op.get("security") == [] or op.get("security") == [{}]:
|
|
652
|
+
score += 2
|
|
653
|
+
reasons.append("unauthenticated")
|
|
654
|
+
|
|
655
|
+
return score, reasons
|
|
656
|
+
|
|
657
|
+
def fetch_spec(url):
|
|
658
|
+
req = Request(url, headers={"User-Agent": UA, "Accept": "application/json"})
|
|
659
|
+
resp = urlopen(req, context=ctx, timeout=20)
|
|
660
|
+
return json.loads(resp.read())
|
|
661
|
+
|
|
662
|
+
parser = argparse.ArgumentParser()
|
|
663
|
+
parser.add_argument("--url", required=True, help="Spec URL")
|
|
664
|
+
parser.add_argument("--base-url", help="Override base URL for attack commands")
|
|
665
|
+
parser.add_argument("--token", default="YOUR_TOKEN_HERE")
|
|
666
|
+
args = parser.parse_args()
|
|
667
|
+
|
|
668
|
+
spec = fetch_spec(args.url)
|
|
669
|
+
|
|
670
|
+
# Determine base URL from spec
|
|
671
|
+
base_url = args.base_url
|
|
672
|
+
if not base_url:
|
|
673
|
+
servers = spec.get("servers", [])
|
|
674
|
+
if servers:
|
|
675
|
+
base_url = servers[0]["url"]
|
|
676
|
+
else:
|
|
677
|
+
base_url = args.url.rsplit("/", 1)[0]
|
|
678
|
+
|
|
679
|
+
# Global auth requirement
|
|
680
|
+
global_security = spec.get("security")
|
|
681
|
+
global_unauth = (global_security == [] or global_security == [{}])
|
|
682
|
+
|
|
683
|
+
# Score and sort all endpoints
|
|
684
|
+
scored = []
|
|
685
|
+
paths = spec.get("paths", {})
|
|
686
|
+
for path, path_item in paths.items():
|
|
687
|
+
for method in ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]:
|
|
688
|
+
op = path_item.get(method.lower())
|
|
689
|
+
if not op:
|
|
690
|
+
continue
|
|
691
|
+
score, reasons = score_endpoint(path, method, op)
|
|
692
|
+
scored.append({
|
|
693
|
+
"score": score,
|
|
694
|
+
"path": path,
|
|
695
|
+
"method": method,
|
|
696
|
+
"op": op,
|
|
697
|
+
"reasons": reasons,
|
|
698
|
+
"summary": op.get("summary", ""),
|
|
699
|
+
"operationId": op.get("operationId", ""),
|
|
700
|
+
})
|
|
701
|
+
|
|
702
|
+
scored.sort(key=lambda x: x["score"], reverse=True)
|
|
703
|
+
|
|
704
|
+
print(f"\n{'='*70}")
|
|
705
|
+
print(f"ATTACK MATRIX — {spec.get('info', {}).get('title', 'Unknown API')}")
|
|
706
|
+
print(f"Base URL: {base_url}")
|
|
707
|
+
print(f"Total endpoints: {len(scored)}")
|
|
708
|
+
print(f"{'='*70}")
|
|
709
|
+
|
|
710
|
+
# Top 20 priority endpoints
|
|
711
|
+
print(f"\n[TOP PRIORITY ENDPOINTS]")
|
|
712
|
+
for ep in scored[:20]:
|
|
713
|
+
auth_flag = "UNAUTH" if any("unauthenticated" in r for r in ep["reasons"]) else "AUTH"
|
|
714
|
+
idor_flag = " [IDOR?]" if any("IDOR" in r for r in ep["reasons"]) else ""
|
|
715
|
+
print(f"\n Score {ep['score']:2d} | [{auth_flag}]{idor_flag} {ep['method']} {ep['path']}")
|
|
716
|
+
print(f" Summary: {ep['summary'][:60]}")
|
|
717
|
+
print(f" Reasons: {', '.join(ep['reasons'])}")
|
|
718
|
+
|
|
719
|
+
# Generate test command
|
|
720
|
+
url = base_url.rstrip("/") + ep["path"]
|
|
721
|
+
# Replace path params with test values
|
|
722
|
+
url_test = re.sub(r'\{[^}]+\}', '1', url)
|
|
723
|
+
if ep["method"] == "GET":
|
|
724
|
+
print(f" Test: curl -s -H 'Authorization: {args.token}' '{url_test}'")
|
|
725
|
+
else:
|
|
726
|
+
print(f" Test: curl -s -X {ep['method']} -H 'Authorization: {args.token}' -H 'Content-Type: application/json' -d '{{}}' '{url_test}'")
|
|
727
|
+
|
|
728
|
+
# Unauthenticated endpoints
|
|
729
|
+
unauth = [ep for ep in scored if any("unauthenticated" in r for r in ep["reasons"])]
|
|
730
|
+
if unauth:
|
|
731
|
+
print(f"\n[UNAUTHENTICATED ENDPOINTS — no token needed]")
|
|
732
|
+
for ep in unauth:
|
|
733
|
+
url = base_url.rstrip("/") + re.sub(r'\{[^}]+\}', '1', ep["path"])
|
|
734
|
+
print(f" {ep['method']} {ep['path']}")
|
|
735
|
+
print(f" curl -s '{url}'")
|
|
736
|
+
|
|
737
|
+
# Internal server URLs for SSRF
|
|
738
|
+
servers = spec.get("servers", [])
|
|
739
|
+
internal = [s["url"] for s in servers if re.search(r'internal|local|corp|\.priv', s.get("url", ""), re.I)]
|
|
740
|
+
if internal:
|
|
741
|
+
print(f"\n[SSRF TARGETS — internal hostnames from servers[]]")
|
|
742
|
+
for h in internal:
|
|
743
|
+
print(f" {h}")
|
|
744
|
+
print(f" → Test SSRF: inject into any URL parameter pointing to {h}")
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
---
|
|
748
|
+
|
|
749
|
+
## Intelligence Extraction Framework
|
|
750
|
+
|
|
751
|
+
### What to Look For in Every Exposed Spec
|
|
752
|
+
|
|
753
|
+
```
|
|
754
|
+
1. servers[] → Internal hostnames (SSRF targets, network topology)
|
|
755
|
+
2. info.version → Environment hints (0.1.0 = dev/alpha, internal build)
|
|
756
|
+
3. security: [] → Global empty = ALL endpoints unauthenticated
|
|
757
|
+
4. paths[*][method].security: [] → Per-operation unauthenticated overrides
|
|
758
|
+
5. components.securitySchemes → Exact auth header names + token types
|
|
759
|
+
6. paths with {id} params → IDOR candidates (every one needs testing)
|
|
760
|
+
7. paths with "admin", "internal" keywords → Vertical access testing
|
|
761
|
+
8. paths with "export", "report", "download" → Data exposure testing
|
|
762
|
+
9. requestBody.content schema → Exact param names for injection/mass assignment
|
|
763
|
+
10. responses[4xx/5xx] schemas → Error oracle shapes for blind testing
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
### Internal Hostname Chain: Spec → SSRF
|
|
767
|
+
|
|
768
|
+
When `servers[]` contains internal hostnames:
|
|
769
|
+
```python
|
|
770
|
+
# Example: spec returns "servers": [{"url": "https://api.glob-use1.internal.faros.ai"}]
|
|
771
|
+
# Attack chain:
|
|
772
|
+
# 1. Note the internal hostname: api.glob-use1.internal.faros.ai
|
|
773
|
+
# 2. Find URL-accepting parameters in the API (webhook URLs, redirect URIs, callback URLs)
|
|
774
|
+
# 3. Test SSRF: does the API make requests to attacker-supplied URLs?
|
|
775
|
+
# 4. If yes: target internal hostname → access internal API without auth
|
|
776
|
+
|
|
777
|
+
# Find URL-type params in spec:
|
|
778
|
+
for path, ops in spec["paths"].items():
|
|
779
|
+
for method, op in ops.items():
|
|
780
|
+
for param in (op.get("parameters") or []):
|
|
781
|
+
if any(k in (param.get("name") or "").lower()
|
|
782
|
+
for k in ["url", "uri", "callback", "redirect", "webhook", "endpoint", "target"]):
|
|
783
|
+
print(f"URL PARAM: {method.upper()} {path} → {param['name']}")
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### Security Scheme → Auth Bypass Testing
|
|
787
|
+
|
|
788
|
+
```python
|
|
789
|
+
# Example: spec discloses {"type": "apiKey", "in": "header", "name": "authorization"}
|
|
790
|
+
# Use this to:
|
|
791
|
+
# 1. Craft requests with exact header name ("authorization" not "Authorization")
|
|
792
|
+
# 2. Test header name case sensitivity
|
|
793
|
+
# 3. Test JWT alg:none against the apiKey scheme
|
|
794
|
+
# 4. Test empty/null/malformed values for 500 vs 401 differential
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
---
|
|
798
|
+
|
|
799
|
+
## Attack Surface
|
|
800
|
+
|
|
801
|
+
- `/docs.json`, `/docs.html` (NestJS/Fastify defaults — frequently missed)
|
|
802
|
+
- `/v3/api-docs`, `/v3/api-docs.yaml` (Spring Boot springdoc-openapi)
|
|
803
|
+
- `/swagger/v1/swagger.json` (.NET / ASP.NET Core)
|
|
804
|
+
- `/documentation/json` (Fastify swagger plugin)
|
|
805
|
+
- `/apispec.json` (Flask-RESTx / Flasgger)
|
|
806
|
+
- `/schema.json`, `/schema/` (Django REST Framework)
|
|
807
|
+
- `/api/documentation` (Laravel l5-swagger)
|
|
808
|
+
- All paths with Swagger UI (`swagger-ui-bundle.js` in page source = doc UI present)
|
|
809
|
+
|
|
810
|
+
## Triage
|
|
811
|
+
|
|
812
|
+
| Finding | Severity | Why |
|
|
813
|
+
|---|---|---|
|
|
814
|
+
| Internal hostname in `servers[]` | MEDIUM-HIGH | SSRF pivot, network topology |
|
|
815
|
+
| Full endpoint inventory exposed | MEDIUM | Eliminates discovery phase for attacker |
|
|
816
|
+
| Unauthenticated endpoints documented | MEDIUM | Confirms attack surface, abuse potential |
|
|
817
|
+
| Auth scheme + header name disclosed | LOW-MEDIUM | Aids auth bypass attempts |
|
|
818
|
+
| Version metadata (`info.version`) | LOW | Environment fingerprinting |
|
|
819
|
+
| Admin/internal endpoint names visible | MEDIUM | Targeted vertical access testing |
|
|
820
|
+
|
|
821
|
+
## Chaining to Higher Severity
|
|
822
|
+
|
|
823
|
+
1. **Spec → SSRF**: Internal hostname in `servers[]` → find URL param in API → SSRF to internal network
|
|
824
|
+
2. **Spec → IDOR**: Endpoint with `{userId}` param → test with victim user ID → data exposure
|
|
825
|
+
3. **Spec → Mass Assignment**: `requestBody.content` reveals all field names including hidden fields → inject admin flags
|
|
826
|
+
4. **Spec → Auth Bypass**: Security scheme discloses exact header name → test null/malformed values → 500 differential
|
|
827
|
+
5. **Spec → Unauthenticated Abuse**: `security: []` endpoints → test for rate-limit abuse, enumeration, data scraping
|
|
828
|
+
|
|
829
|
+
## Validation Requirements
|
|
830
|
+
|
|
831
|
+
- `GET /docs.json → HTTP 200 (no Authorization header)` — unauthenticated access confirmed
|
|
832
|
+
- Spec body contains valid JSON/YAML with `openapi`/`swagger` key
|
|
833
|
+
- `servers[]` contains at minimum one URL; note if any match internal hostname patterns
|
|
834
|
+
- `components.securitySchemes` documents auth header name/type
|
|
835
|
+
- `paths` count > N confirms full inventory exposure
|
|
836
|
+
- At least one `security: []` per-operation to confirm unauthenticated endpoint documented
|
|
837
|
+
|
|
838
|
+
## False Positives
|
|
839
|
+
|
|
840
|
+
- Intentionally public API docs with no internal topology leakage (servers[] = public URL only)
|
|
841
|
+
- Docs behind authentication (check if auth gate on `/docs.json` applies)
|
|
842
|
+
- Version metadata with no sensitive content (info.version alone is LOW/informational)
|
|
843
|
+
|
|
844
|
+
## Bug Bounty Acceptance Scoring
|
|
845
|
+
|
|
846
|
+
- **Internal hostname in servers[]**: 7/10 — real infrastructure disclosure, chains to SSRF
|
|
847
|
+
- **Full endpoint inventory only**: 5/10 — informational unless combined with finding
|
|
848
|
+
- **Unauthenticated endpoint via spec**: escalates to 8/10 if data returned
|
|
849
|
+
- **Would this be accepted?**: YES for MEDIUM if internal hostname present; YES for LOW if just endpoint count
|