@devo-bmad-custom/agent-orchestration 1.0.2 → 1.0.3
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/lib/installer.js +33 -0
- package/package.json +1 -1
- package/src/.agents/skills/audit-website/README.md +20 -20
- package/src/.agents/skills/audit-website/SKILL.md +470 -470
- package/src/.agents/skills/audit-website/agents/openai.yaml +6 -6
- package/src/.agents/skills/audit-website/assets/icon-small.svg +41 -41
- package/src/.agents/skills/audit-website/references/OUTPUT-FORMAT.md +250 -250
- package/src/.agents/skills/clean-code-standards/SKILL.md +104 -104
- package/src/.agents/skills/excalidraw-dark-standard/SKILL.md +281 -281
- package/src/.agents/skills/frontend-responsive-design-standards/SKILL.md +434 -434
- package/src/.agents/skills/java-fundamentals/SKILL.md +116 -116
- package/src/.agents/skills/java-performance/SKILL.md +119 -119
- package/src/.agents/skills/next-best-practices/SKILL.md +153 -153
- package/src/.agents/skills/next-best-practices/async-patterns.md +87 -87
- package/src/.agents/skills/next-best-practices/bundling.md +180 -180
- package/src/.agents/skills/next-best-practices/data-patterns.md +297 -297
- package/src/.agents/skills/next-best-practices/debug-tricks.md +105 -105
- package/src/.agents/skills/next-best-practices/directives.md +73 -73
- package/src/.agents/skills/next-best-practices/error-handling.md +227 -227
- package/src/.agents/skills/next-best-practices/file-conventions.md +140 -140
- package/src/.agents/skills/next-best-practices/font.md +245 -245
- package/src/.agents/skills/next-best-practices/functions.md +108 -108
- package/src/.agents/skills/next-best-practices/hydration-error.md +91 -91
- package/src/.agents/skills/next-best-practices/image.md +173 -173
- package/src/.agents/skills/next-best-practices/metadata.md +301 -301
- package/src/.agents/skills/next-best-practices/parallel-routes.md +287 -287
- package/src/.agents/skills/next-best-practices/route-handlers.md +146 -146
- package/src/.agents/skills/next-best-practices/rsc-boundaries.md +159 -159
- package/src/.agents/skills/next-best-practices/runtime-selection.md +39 -39
- package/src/.agents/skills/next-best-practices/scripts.md +141 -141
- package/src/.agents/skills/next-best-practices/self-hosting.md +371 -371
- package/src/.agents/skills/next-best-practices/suspense-boundaries.md +67 -67
- package/src/.agents/skills/nextjs-app-router-patterns/SKILL.md +537 -537
- package/src/.agents/skills/postgresql-optimization/SKILL.md +404 -404
- package/src/.agents/skills/python-backend/SKILL.md +153 -153
- package/src/.agents/skills/python-fundamentals/SKILL.md +234 -234
- package/src/.agents/skills/python-performance/SKILL.md +404 -404
- package/src/.agents/skills/react-expert/SKILL.md +335 -335
- package/src/.agents/skills/redis-best-practices/SKILL.md +438 -438
- package/src/.agents/skills/security-best-practices/SKILL.md +288 -288
- package/src/.agents/skills/security-review/LICENSE +22 -22
- package/src/.agents/skills/security-review/SKILL.md +312 -312
- package/src/.agents/skills/security-review/infrastructure/docker.md +432 -432
- package/src/.agents/skills/security-review/languages/javascript.md +388 -388
- package/src/.agents/skills/security-review/languages/python.md +363 -363
- package/src/.agents/skills/security-review/references/api-security.md +519 -519
- package/src/.agents/skills/security-review/references/authentication.md +353 -353
- package/src/.agents/skills/security-review/references/authorization.md +372 -372
- package/src/.agents/skills/security-review/references/business-logic.md +443 -443
- package/src/.agents/skills/security-review/references/cryptography.md +329 -329
- package/src/.agents/skills/security-review/references/csrf.md +398 -398
- package/src/.agents/skills/security-review/references/data-protection.md +378 -378
- package/src/.agents/skills/security-review/references/deserialization.md +410 -410
- package/src/.agents/skills/security-review/references/error-handling.md +436 -436
- package/src/.agents/skills/security-review/references/file-security.md +457 -457
- package/src/.agents/skills/security-review/references/injection.md +259 -259
- package/src/.agents/skills/security-review/references/logging.md +433 -433
- package/src/.agents/skills/security-review/references/misconfiguration.md +435 -435
- package/src/.agents/skills/security-review/references/modern-threats.md +475 -475
- package/src/.agents/skills/security-review/references/ssrf.md +415 -415
- package/src/.agents/skills/security-review/references/supply-chain.md +405 -405
- package/src/.agents/skills/security-review/references/xss.md +336 -336
- package/src/.agents/skills/subagent-driven-development/SKILL.md +275 -275
- package/src/.agents/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -26
- package/src/.agents/skills/subagent-driven-development/implementer-prompt.md +113 -113
- package/src/.agents/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -61
- package/src/.agents/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/src/.agents/skills/systematic-debugging/SKILL.md +296 -296
- package/src/.agents/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/src/.agents/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/src/.agents/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/src/.agents/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/src/.agents/skills/systematic-debugging/test-academic.md +14 -14
- package/src/.agents/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/src/.agents/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/src/.agents/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/src/.agents/skills/typescript-best-practices/SKILL.md +373 -373
- package/src/.agents/skills/ui-ux-pro-custom/SKILL.md +348 -348
- package/src/.agents/skills/ui-ux-pro-custom/data/charts.csv +26 -26
- package/src/.agents/skills/ui-ux-pro-custom/data/colors.csv +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/icons.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/SKILL.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/accessibility.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/animation.md +466 -466
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/composition-locals.md +231 -231
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/deprecated-patterns.md +323 -323
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/lists-scrolling.md +400 -400
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/modifiers.md +331 -331
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/navigation.md +416 -416
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/performance.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/side-effects.md +516 -516
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/foundation-source.md +13327 -13327
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/material3-source.md +19097 -19097
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/navigation-source.md +2947 -2947
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/runtime-source.md +11316 -11316
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/ui-source.md +7896 -7896
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/state-management.md +377 -377
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/styles-experimental.md +470 -470
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/theming-material3.md +349 -349
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/view-composition.md +595 -595
- package/src/.agents/skills/ui-ux-pro-custom/data/landing.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/data/mobile-ui-layout.md +654 -654
- package/src/.agents/skills/ui-ux-pro-custom/data/products.csv +96 -96
- package/src/.agents/skills/ui-ux-pro-custom/data/react-performance.csv +45 -45
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/astro.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/flutter.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/html-tailwind.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/jetpack-compose.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nextjs.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxt-ui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxtjs.csv +59 -59
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react-native.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/shadcn.csv +61 -61
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/svelte.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/swiftui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/vue.csv +50 -50
- package/src/.agents/skills/ui-ux-pro-custom/data/styles.csv +68 -68
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/SKILL.md +438 -438
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/references/alarmkit-patterns.md +584 -584
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-clips/SKILL.md +436 -436
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/SKILL.md +489 -489
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/references/appintents-advanced.md +1076 -1076
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/SKILL.md +340 -340
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/privacy-manifest.md +90 -90
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/review-checklists.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-conversion.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-optimization.md +344 -344
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/foundation-models.md +508 -508
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/mlx-swift.md +285 -285
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/references/keychain-biometric.md +211 -211
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/SKILL.md +499 -499
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/references/background-task-patterns.md +390 -390
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/SKILL.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/references/callkit-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/SKILL.md +492 -492
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/references/cloudkit-patterns.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/codable-patterns/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/SKILL.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/references/contacts-patterns.md +409 -409
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/references/ble-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/SKILL.md +388 -388
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/references/motion-patterns.md +405 -405
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/SKILL.md +495 -495
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/references/nfc-patterns.md +420 -420
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/SKILL.md +459 -459
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/references/coreml-swift-integration.md +765 -765
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/SKILL.md +422 -422
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/instruments-guide.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/lldb-patterns.md +298 -298
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/device-integrity/SKILL.md +477 -477
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/SKILL.md +460 -460
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/references/energykit-patterns.md +541 -541
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/references/eventkit-patterns.md +326 -326
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/references/healthkit-patterns.md +602 -602
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/references/matter-commissioning.md +455 -455
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/SKILL.md +301 -301
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/references/a11y-patterns.md +140 -140
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/SKILL.md +418 -418
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/formatstyle-locale.md +627 -627
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/string-catalogs.md +462 -462
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/SKILL.md +441 -441
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/background-websocket.md +862 -862
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/lightweight-clients.md +93 -93
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/network-framework.md +563 -563
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/urlsession-patterns.md +1116 -1116
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/app-review-guidelines.md +174 -174
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/cryptokit-advanced.md +296 -296
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/file-storage-patterns.md +354 -354
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/privacy-manifest.md +117 -117
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/references/live-activity-patterns.md +868 -868
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/corelocation-patterns.md +730 -730
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/mapkit-patterns.md +748 -748
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/metrickit-diagnostics/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/SKILL.md +395 -395
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/references/musickit-patterns.md +363 -363
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/SKILL.md +412 -412
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/references/translation-patterns.md +311 -311
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/SKILL.md +398 -398
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/references/wallet-passes.md +254 -254
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/SKILL.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/paperkit-integration.md +376 -376
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/pencilkit-patterns.md +302 -302
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/SKILL.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/references/permissionkit-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/av-playback.md +701 -701
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/camera-capture.md +774 -774
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/image-loading-caching.md +869 -869
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/photospicker-patterns.md +597 -597
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/notification-patterns.md +677 -677
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/rich-notifications.md +745 -745
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/references/realitykit-patterns.md +480 -480
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/references/shareplay-patterns.md +544 -544
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/speech-recognition/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/SKILL.md +478 -478
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/app-review-guidelines.md +58 -58
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/storekit-advanced.md +755 -755
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/SKILL.md +487 -487
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/references/charts-patterns.md +895 -895
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/SKILL.md +408 -408
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/approachable-concurrency.md +80 -80
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swift-6-2-concurrency.md +233 -233
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swiftui-concurrency.md +187 -187
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/synchronization-primitives.md +341 -341
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/references/swift-patterns-extended.md +505 -505
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/references/testing-patterns.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/SKILL.md +334 -334
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/core-data-coexistence.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-advanced.md +975 -975
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-queries.md +675 -675
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/SKILL.md +481 -481
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/animation-advanced.md +804 -804
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/core-animation-bridge.md +553 -553
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/SKILL.md +450 -450
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/references/gesture-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/SKILL.md +336 -336
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/form.md +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/grids.md +69 -69
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/list.md +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/scrollview.md +147 -147
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/SKILL.md +325 -325
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/references/liquid-glass.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/SKILL.md +262 -262
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/deeplinks.md +207 -207
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/navigationstack.md +177 -177
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/sheets.md +169 -169
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/tabview.md +178 -178
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/SKILL.md +381 -381
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/architecture-patterns.md +486 -486
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/deprecated-migration.md +1097 -1097
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/design-polish.md +780 -780
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/platform-and-sharing.md +696 -696
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +46 -46
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +29 -29
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-hangs-in-your-app.md +33 -33
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-improving-swiftui-performance.md +52 -52
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/SKILL.md +428 -428
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/hosting-migration.md +534 -534
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/representable-recipes.md +1133 -1133
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/SKILL.md +494 -494
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/references/tipkit-patterns.md +782 -782
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/SKILL.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/vision-requests.md +736 -736
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/visionkit-scanner.md +738 -738
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/SKILL.md +410 -410
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/references/weatherkit-patterns.md +567 -567
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/SKILL.md +497 -497
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/references/widgetkit-advanced.md +871 -871
- package/src/.agents/skills/ui-ux-pro-custom/data/typography.csv +57 -57
- package/src/.agents/skills/ui-ux-pro-custom/data/ui-reasoning.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/ux-guidelines.csv +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/web-interface.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/scripts/core.py +253 -253
- package/src/.agents/skills/ui-ux-pro-custom/scripts/design_system.py +1067 -1067
- package/src/.agents/skills/ui-ux-pro-custom/scripts/search.py +114 -114
- package/src/.agents/skills/ux-audit/SKILL.md +150 -150
- package/src/.agents/skills/websocket-engineer/SKILL.md +168 -168
- package/src/.agents/skills/websocket-engineer/references/alternatives.md +391 -391
- package/src/.agents/skills/websocket-engineer/references/patterns.md +400 -400
- package/src/.agents/skills/websocket-engineer/references/protocol.md +195 -195
- package/src/.agents/skills/websocket-engineer/references/scaling.md +333 -333
- package/src/.agents/skills/websocket-engineer/references/security.md +474 -474
- package/src/.agents/skills/writing-skills/SKILL.md +655 -655
- package/src/.agents/skills/writing-skills/anthropic-best-practices.md +1150 -1150
- package/src/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/src/.agents/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/src/.agents/skills/writing-skills/persuasion-principles.md +187 -187
- package/src/.agents/skills/writing-skills/render-graphs.js +168 -168
- package/src/.agents/skills/writing-skills/testing-skills-with-subagents.md +384 -384
- package/src/.claude/commands/master-orchestrator.md +15 -0
- package/src/_memory/config.yaml +11 -11
- package/src/_memory/master-orchestrator-sidecar/instructions.md +85 -32
- package/src/_memory/skills/nimbalyst-tracking/SKILL.md +103 -103
- package/src/_memory/skills/writing-skills/SKILL.md +655 -655
- package/src/bmb/agents/agent-builder.md +59 -59
- package/src/bmb/agents/module-builder.md +60 -60
- package/src/bmb/agents/workflow-builder.md +61 -61
- package/src/bmb/config.yaml +12 -12
- package/src/bmb/module-help.csv +13 -13
- package/src/bmb/workflows/agent/data/agent-architecture.md +258 -258
- package/src/bmb/workflows/agent/data/agent-compilation.md +185 -185
- package/src/bmb/workflows/agent/data/agent-menu-patterns.md +189 -189
- package/src/bmb/workflows/agent/data/agent-metadata.md +133 -133
- package/src/bmb/workflows/agent/data/agent-validation.md +111 -111
- package/src/bmb/workflows/agent/data/brainstorm-context.md +96 -96
- package/src/bmb/workflows/agent/data/communication-presets.csv +61 -61
- package/src/bmb/workflows/agent/data/critical-actions.md +75 -75
- package/src/bmb/workflows/agent/data/persona-properties.md +252 -252
- package/src/bmb/workflows/agent/data/principles-crafting.md +142 -142
- package/src/bmb/workflows/agent/data/reference/module-examples/architect.md +68 -68
- package/src/bmb/workflows/agent/data/reference/with-sidecar/journal-keeper/journal-keeper-sidecar/entries/yy-mm-dd-entry-template.md +16 -16
- package/src/bmb/workflows/agent/data/understanding-agent-types.md +126 -126
- package/src/bmb/workflows/agent/steps-c/step-01-brainstorm.md +129 -129
- package/src/bmb/workflows/agent/steps-c/step-02-discovery.md +170 -170
- package/src/bmb/workflows/agent/steps-c/step-03-sidecar-metadata.md +309 -309
- package/src/bmb/workflows/agent/steps-c/step-04-persona.md +213 -213
- package/src/bmb/workflows/agent/steps-c/step-05-commands-menu.md +179 -179
- package/src/bmb/workflows/agent/steps-c/step-06-activation.md +278 -278
- package/src/bmb/workflows/agent/steps-c/step-07-build-agent.md +316 -316
- package/src/bmb/workflows/agent/steps-c/step-08-celebrate.md +247 -247
- package/src/bmb/workflows/agent/steps-e/e-01-load-existing.md +221 -221
- package/src/bmb/workflows/agent/steps-e/e-02-discover-edits.md +195 -195
- package/src/bmb/workflows/agent/steps-e/e-04-sidecar-metadata.md +126 -126
- package/src/bmb/workflows/agent/steps-e/e-05-persona.md +135 -135
- package/src/bmb/workflows/agent/steps-e/e-06-commands-menu.md +123 -123
- package/src/bmb/workflows/agent/steps-e/e-07-activation.md +124 -124
- package/src/bmb/workflows/agent/steps-e/e-08-edit-agent.md +197 -197
- package/src/bmb/workflows/agent/steps-e/e-09-celebrate.md +155 -155
- package/src/bmb/workflows/agent/steps-v/v-01-load-review.md +137 -137
- package/src/bmb/workflows/agent/steps-v/v-02a-validate-metadata.md +116 -116
- package/src/bmb/workflows/agent/steps-v/v-02b-validate-persona.md +124 -124
- package/src/bmb/workflows/agent/steps-v/v-02c-validate-menu.md +127 -127
- package/src/bmb/workflows/agent/steps-v/v-02d-validate-structure.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-02e-validate-sidecar.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-03-summary.md +104 -104
- package/src/bmb/workflows/agent/templates/agent-plan.template.md +5 -5
- package/src/bmb/workflows/agent/templates/agent-template.md +89 -89
- package/src/bmb/workflows/agent/workflow-create-agent.md +72 -72
- package/src/bmb/workflows/agent/workflow-edit-agent.md +75 -75
- package/src/bmb/workflows/agent/workflow-validate-agent.md +73 -73
- package/src/bmb/workflows/module/data/agent-architecture.md +179 -179
- package/src/bmb/workflows/module/data/agent-spec-template.md +79 -79
- package/src/bmb/workflows/module/data/module-standards.md +263 -263
- package/src/bmb/workflows/module/data/module-yaml-conventions.md +392 -392
- package/src/bmb/workflows/module/module-help-generate.md +254 -254
- package/src/bmb/workflows/module/steps-b/step-01-welcome.md +148 -148
- package/src/bmb/workflows/module/steps-b/step-02-spark.md +141 -141
- package/src/bmb/workflows/module/steps-b/step-03-module-type.md +149 -149
- package/src/bmb/workflows/module/steps-b/step-04-vision.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-05-identity.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-06-users.md +86 -86
- package/src/bmb/workflows/module/steps-b/step-07-value.md +76 -76
- package/src/bmb/workflows/module/steps-b/step-08-agents.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-09-workflows.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-10-tools.md +91 -91
- package/src/bmb/workflows/module/steps-b/step-11-scenarios.md +84 -84
- package/src/bmb/workflows/module/steps-b/step-12-creative.md +95 -95
- package/src/bmb/workflows/module/steps-b/step-13-review.md +105 -105
- package/src/bmb/workflows/module/steps-b/step-14-finalize.md +117 -117
- package/src/bmb/workflows/module/steps-c/step-01-load-brief.md +179 -179
- package/src/bmb/workflows/module/steps-c/step-01b-continue.md +82 -82
- package/src/bmb/workflows/module/steps-c/step-02-structure.md +105 -105
- package/src/bmb/workflows/module/steps-c/step-03-config.md +119 -119
- package/src/bmb/workflows/module/steps-c/step-04-agents.md +168 -168
- package/src/bmb/workflows/module/steps-c/step-05-workflows.md +184 -184
- package/src/bmb/workflows/module/steps-c/step-06-docs.md +401 -401
- package/src/bmb/workflows/module/steps-c/step-07-complete.md +152 -152
- package/src/bmb/workflows/module/steps-e/step-01-load-target.md +81 -81
- package/src/bmb/workflows/module/steps-e/step-02-select-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-03-apply-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-04-review.md +80 -80
- package/src/bmb/workflows/module/steps-e/step-05-confirm.md +75 -75
- package/src/bmb/workflows/module/steps-v/step-01-load-target.md +96 -96
- package/src/bmb/workflows/module/steps-v/step-02-file-structure.md +93 -93
- package/src/bmb/workflows/module/steps-v/step-03-module-yaml.md +99 -99
- package/src/bmb/workflows/module/steps-v/step-04-agent-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-05-workflow-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-06-documentation.md +143 -143
- package/src/bmb/workflows/module/steps-v/step-07-installation.md +102 -102
- package/src/bmb/workflows/module/steps-v/step-08-report.md +197 -197
- package/src/bmb/workflows/module/templates/brief-template.md +154 -154
- package/src/bmb/workflows/module/templates/workflow-spec-template.md +96 -96
- package/src/bmb/workflows/module/workflow-create-module-brief.md +71 -71
- package/src/bmb/workflows/module/workflow-create-module.md +86 -86
- package/src/bmb/workflows/module/workflow-edit-module.md +66 -66
- package/src/bmb/workflows/module/workflow-validate-module.md +66 -66
- package/src/bmb/workflows/workflow/data/architecture.md +150 -150
- package/src/bmb/workflows/workflow/data/common-workflow-tools.csv +19 -19
- package/src/bmb/workflows/workflow/data/csv-data-file-standards.md +53 -53
- package/src/bmb/workflows/workflow/data/frontmatter-standards.md +184 -184
- package/src/bmb/workflows/workflow/data/input-discovery-standards.md +191 -191
- package/src/bmb/workflows/workflow/data/intent-vs-prescriptive-spectrum.md +44 -44
- package/src/bmb/workflows/workflow/data/menu-handling-standards.md +133 -133
- package/src/bmb/workflows/workflow/data/output-format-standards.md +135 -135
- package/src/bmb/workflows/workflow/data/step-file-rules.md +235 -235
- package/src/bmb/workflows/workflow/data/step-type-patterns.md +257 -257
- package/src/bmb/workflows/workflow/data/subprocess-optimization-patterns.md +188 -188
- package/src/bmb/workflows/workflow/data/trimodal-workflow-structure.md +164 -164
- package/src/bmb/workflows/workflow/data/workflow-chaining-standards.md +222 -222
- package/src/bmb/workflows/workflow/data/workflow-examples.md +232 -232
- package/src/bmb/workflows/workflow/data/workflow-type-criteria.md +134 -134
- package/src/bmb/workflows/workflow/steps-c/step-00-conversion.md +263 -263
- package/src/bmb/workflows/workflow/steps-c/step-01-discovery.md +194 -194
- package/src/bmb/workflows/workflow/steps-c/step-01b-continuation.md +3 -3
- package/src/bmb/workflows/workflow/steps-c/step-02-classification.md +270 -270
- package/src/bmb/workflows/workflow/steps-c/step-03-requirements.md +283 -283
- package/src/bmb/workflows/workflow/steps-c/step-04-tools.md +282 -282
- package/src/bmb/workflows/workflow/steps-c/step-05-plan-review.md +243 -243
- package/src/bmb/workflows/workflow/steps-c/step-06-design.md +330 -330
- package/src/bmb/workflows/workflow/steps-c/step-07-foundation.md +239 -239
- package/src/bmb/workflows/workflow/steps-c/step-08-build-step-01.md +379 -379
- package/src/bmb/workflows/workflow/steps-c/step-09-build-next-step.md +350 -350
- package/src/bmb/workflows/workflow/steps-c/step-10-confirmation.md +322 -322
- package/src/bmb/workflows/workflow/steps-c/step-11-completion.md +191 -191
- package/src/bmb/workflows/workflow/steps-e/step-e-01-assess-workflow.md +237 -237
- package/src/bmb/workflows/workflow/steps-e/step-e-02-discover-edits.md +251 -251
- package/src/bmb/workflows/workflow/steps-e/step-e-03-fix-validation.md +254 -254
- package/src/bmb/workflows/workflow/steps-e/step-e-04-direct-edit.md +277 -277
- package/src/bmb/workflows/workflow/steps-e/step-e-05-apply-edit.md +154 -154
- package/src/bmb/workflows/workflow/steps-e/step-e-06-validate-after.md +190 -190
- package/src/bmb/workflows/workflow/steps-e/step-e-07-complete.md +206 -206
- package/src/bmb/workflows/workflow/steps-v/step-01-validate-max-mode.md +109 -109
- package/src/bmb/workflows/workflow/steps-v/step-01-validate.md +221 -221
- package/src/bmb/workflows/workflow/steps-v/step-01b-structure.md +152 -152
- package/src/bmb/workflows/workflow/steps-v/step-02-frontmatter-validation.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-02b-path-violations.md +265 -265
- package/src/bmb/workflows/workflow/steps-v/step-03-menu-validation.md +164 -164
- package/src/bmb/workflows/workflow/steps-v/step-04-step-type-validation.md +211 -211
- package/src/bmb/workflows/workflow/steps-v/step-05-output-format-validation.md +200 -200
- package/src/bmb/workflows/workflow/steps-v/step-06-validation-design-check.md +195 -195
- package/src/bmb/workflows/workflow/steps-v/step-07-instruction-style-check.md +209 -209
- package/src/bmb/workflows/workflow/steps-v/step-08-collaborative-experience-check.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-08b-subprocess-optimization.md +179 -179
- package/src/bmb/workflows/workflow/steps-v/step-09-cohesive-review.md +186 -186
- package/src/bmb/workflows/workflow/steps-v/step-10-report-complete.md +154 -154
- package/src/bmb/workflows/workflow/steps-v/step-11-plan-validation.md +237 -237
- package/src/bmb/workflows/workflow/templates/minimal-output-template.md +11 -11
- package/src/bmb/workflows/workflow/templates/step-01-init-continuable-template.md +241 -241
- package/src/bmb/workflows/workflow/templates/step-1b-template.md +224 -224
- package/src/bmb/workflows/workflow/templates/step-template.md +294 -294
- package/src/bmb/workflows/workflow/templates/workflow-template.md +102 -102
- package/src/bmb/workflows/workflow/workflow-create-workflow.md +79 -79
- package/src/bmb/workflows/workflow/workflow-edit-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-rework-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-validate-max-parallel-workflow.md +66 -66
- package/src/bmb/workflows/workflow/workflow-validate-workflow.md +65 -65
- package/src/bmm/agents/analyst.md +104 -104
- package/src/bmm/agents/dev.md +100 -100
- package/src/bmm/agents/qa.md +100 -90
- package/src/bmm/agents/tech-writer/tech-writer.md +94 -94
- package/src/bmm/module-help.csv +31 -31
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +115 -115
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +107 -107
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +141 -141
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +144 -144
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +147 -147
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +161 -161
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +99 -99
- package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +57 -57
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +156 -156
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +165 -165
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +140 -140
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +152 -152
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +345 -345
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +92 -92
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +164 -164
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +174 -174
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +184 -184
- package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +105 -105
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +360 -360
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +165 -165
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +174 -174
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +141 -141
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +159 -159
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +387 -387
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -54
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +100 -100
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +160 -160
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +88 -88
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +99 -99
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +169 -169
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +156 -156
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +176 -176
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +184 -184
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +174 -174
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +175 -175
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +189 -189
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +162 -162
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +79 -79
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +183 -183
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +149 -149
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +187 -187
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +108 -108
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +166 -166
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +131 -131
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +150 -150
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +155 -155
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +170 -170
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +158 -158
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +147 -147
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +182 -182
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +202 -202
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +148 -148
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +201 -201
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +179 -179
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +164 -164
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +106 -106
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +111 -111
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +115 -115
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +127 -127
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +167 -167
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +143 -143
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +154 -154
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +165 -165
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +135 -135
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +101 -101
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +45 -45
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +185 -185
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +130 -130
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +93 -93
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +196 -196
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -54
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +82 -82
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +106 -106
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +138 -138
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +129 -129
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +166 -166
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +186 -186
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +163 -163
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +38 -38
- package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +49 -49
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +124 -124
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +122 -122
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +84 -84
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -58
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +43 -43
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +53 -53
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +159 -159
- package/src/bmm/workflows/4-implementation/create-story/template.md +79 -79
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +20 -20
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +25 -25
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +158 -158
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +122 -122
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +87 -87
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -146
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -50
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +152 -152
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +123 -123
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +201 -201
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -79
- package/src/bmm/workflows/document-project/workflow.yaml +22 -22
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +184 -184
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +322 -322
- package/src/bmm/workflows/generate-project-context/steps/step-03-complete.md +235 -235
- package/src/bmm/workflows/generate-project-context/workflow.md +49 -49
- package/src/bmm/workflows/qa/automate/workflow.yaml +233 -233
- package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +42 -42
- package/src/core/config.yaml +9 -9
- package/src/core/module-help.csv +10 -10
- package/src/core/scripts/generate-loop-report.py +72 -72
- package/src/core/tasks/editorial-review-prose.xml +101 -101
- package/src/core/tasks/editorial-review-structure.xml +207 -207
- package/src/core/tasks/help.md +86 -86
- package/src/core/tasks/index-docs.xml +64 -64
- package/src/core/tasks/review-adversarial-general.xml +66 -66
- package/src/core/tasks/review-adversarial-loop.xml +46 -46
- package/src/core/tasks/review-edge-case-hunter.xml +63 -63
- package/src/core/tasks/review-party-loop.xml +46 -46
- package/src/core/tasks/shard-doc.xml +107 -107
- package/src/core/tasks/workflow.xml +235 -235
- package/src/core/templates/review-loop-report.html +88 -88
- package/src/core/templates/review-loop-report.md +5 -5
- package/src/core/workflows/advanced-elicitation/workflow.xml +117 -117
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +212 -212
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -122
- package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -225
- package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -237
- package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -209
- package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -264
- package/src/core/workflows/brainstorming/steps/step-02e-deep-dive.md +68 -68
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +403 -403
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -303
- package/src/core/workflows/brainstorming/workflow.md +60 -60
- package/src/core/workflows/extract-trackers/workflow.md +45 -45
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +142 -142
- package/src/core/workflows/party-mode/workflow.md +194 -194
- package/src/docs/dev/tmux/actions_popup.py +291 -291
- package/src/docs/dev/tmux/tmux-setup.md +62 -1
|
@@ -1,457 +1,457 @@
|
|
|
1
|
-
# File Security Reference
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
File operations present multiple security risks: path traversal attacks, malicious file uploads, XML External Entity (XXE) attacks, and insecure file permissions. This reference covers secure patterns for handling files.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Path Traversal Prevention
|
|
10
|
-
|
|
11
|
-
### The Vulnerability
|
|
12
|
-
|
|
13
|
-
```python
|
|
14
|
-
# VULNERABLE: User-controlled path
|
|
15
|
-
@app.route('/download')
|
|
16
|
-
def download():
|
|
17
|
-
filename = request.args.get('file')
|
|
18
|
-
return send_file(f'/uploads/{filename}')
|
|
19
|
-
|
|
20
|
-
# Attack: ?file=../../../etc/passwd
|
|
21
|
-
# Results in: /uploads/../../../etc/passwd → /etc/passwd
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Prevention Techniques
|
|
25
|
-
|
|
26
|
-
```python
|
|
27
|
-
import os
|
|
28
|
-
from pathlib import Path
|
|
29
|
-
|
|
30
|
-
# Method 1: Validate and canonicalize path
|
|
31
|
-
def safe_join(base_directory, user_path):
|
|
32
|
-
"""Safely join paths, preventing traversal."""
|
|
33
|
-
# Resolve to absolute path
|
|
34
|
-
base = Path(base_directory).resolve()
|
|
35
|
-
target = (base / user_path).resolve()
|
|
36
|
-
|
|
37
|
-
# Verify target is under base
|
|
38
|
-
if not str(target).startswith(str(base)):
|
|
39
|
-
raise ValueError("Path traversal detected")
|
|
40
|
-
|
|
41
|
-
return str(target)
|
|
42
|
-
|
|
43
|
-
# Method 2: Use allowlist of files
|
|
44
|
-
ALLOWED_FILES = {'report.pdf', 'manual.pdf', 'readme.txt'}
|
|
45
|
-
|
|
46
|
-
def download_file(filename):
|
|
47
|
-
if filename not in ALLOWED_FILES:
|
|
48
|
-
raise ValueError("File not allowed")
|
|
49
|
-
return send_file(os.path.join(UPLOAD_DIR, filename))
|
|
50
|
-
|
|
51
|
-
# Method 3: Use indirect references
|
|
52
|
-
def get_file_by_id(file_id):
|
|
53
|
-
# Map ID to filename in database
|
|
54
|
-
file_record = File.query.get(file_id)
|
|
55
|
-
if not file_record or file_record.user_id != current_user.id:
|
|
56
|
-
raise PermissionError()
|
|
57
|
-
return send_file(file_record.storage_path)
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Characters to Block
|
|
61
|
-
|
|
62
|
-
```python
|
|
63
|
-
# Dangerous path patterns
|
|
64
|
-
BLOCKED_PATTERNS = [
|
|
65
|
-
'..', # Parent directory
|
|
66
|
-
'~', # Home directory
|
|
67
|
-
'%2e%2e', # URL-encoded ..
|
|
68
|
-
'%252e%252e', # Double-encoded ..
|
|
69
|
-
'..\\', # Windows backslash
|
|
70
|
-
'..%5c', # URL-encoded Windows
|
|
71
|
-
'%00', # Null byte (older systems)
|
|
72
|
-
]
|
|
73
|
-
|
|
74
|
-
def contains_traversal(path):
|
|
75
|
-
path_lower = path.lower()
|
|
76
|
-
return any(pattern in path_lower for pattern in BLOCKED_PATTERNS)
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## File Upload Security
|
|
82
|
-
|
|
83
|
-
### Defense in Depth Approach
|
|
84
|
-
|
|
85
|
-
```python
|
|
86
|
-
import magic
|
|
87
|
-
import hashlib
|
|
88
|
-
import uuid
|
|
89
|
-
from pathlib import Path
|
|
90
|
-
|
|
91
|
-
# Configuration
|
|
92
|
-
ALLOWED_EXTENSIONS = {'pdf', 'png', 'jpg', 'jpeg', 'gif'}
|
|
93
|
-
ALLOWED_MIMETYPES = {
|
|
94
|
-
'application/pdf',
|
|
95
|
-
'image/png',
|
|
96
|
-
'image/jpeg',
|
|
97
|
-
'image/gif'
|
|
98
|
-
}
|
|
99
|
-
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
|
|
100
|
-
UPLOAD_DIR = '/var/uploads' # Outside webroot
|
|
101
|
-
|
|
102
|
-
def secure_upload(file):
|
|
103
|
-
"""Comprehensive file upload validation."""
|
|
104
|
-
|
|
105
|
-
# 1. Check file size
|
|
106
|
-
file.seek(0, 2) # Seek to end
|
|
107
|
-
size = file.tell()
|
|
108
|
-
file.seek(0) # Reset
|
|
109
|
-
if size > MAX_FILE_SIZE:
|
|
110
|
-
raise ValueError(f"File too large: {size} bytes")
|
|
111
|
-
|
|
112
|
-
# 2. Validate extension
|
|
113
|
-
original_filename = file.filename
|
|
114
|
-
extension = Path(original_filename).suffix.lower().lstrip('.')
|
|
115
|
-
if extension not in ALLOWED_EXTENSIONS:
|
|
116
|
-
raise ValueError(f"Extension not allowed: {extension}")
|
|
117
|
-
|
|
118
|
-
# 3. Validate MIME type (don't trust Content-Type header)
|
|
119
|
-
mime = magic.from_buffer(file.read(2048), mime=True)
|
|
120
|
-
file.seek(0)
|
|
121
|
-
if mime not in ALLOWED_MIMETYPES:
|
|
122
|
-
raise ValueError(f"MIME type not allowed: {mime}")
|
|
123
|
-
|
|
124
|
-
# 4. Validate extension matches content
|
|
125
|
-
expected_extensions = get_extensions_for_mime(mime)
|
|
126
|
-
if extension not in expected_extensions:
|
|
127
|
-
raise ValueError("Extension doesn't match content type")
|
|
128
|
-
|
|
129
|
-
# 5. Generate safe filename (ignore user input)
|
|
130
|
-
safe_filename = f"{uuid.uuid4().hex}.{extension}"
|
|
131
|
-
|
|
132
|
-
# 6. Store outside webroot
|
|
133
|
-
storage_path = os.path.join(UPLOAD_DIR, safe_filename)
|
|
134
|
-
file.save(storage_path)
|
|
135
|
-
|
|
136
|
-
# 7. Set restrictive permissions
|
|
137
|
-
os.chmod(storage_path, 0o640)
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
'original_name': original_filename,
|
|
141
|
-
'stored_name': safe_filename,
|
|
142
|
-
'storage_path': storage_path,
|
|
143
|
-
'size': size,
|
|
144
|
-
'mime_type': mime
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Filename Sanitization
|
|
149
|
-
|
|
150
|
-
```python
|
|
151
|
-
import re
|
|
152
|
-
import unicodedata
|
|
153
|
-
|
|
154
|
-
def sanitize_filename(filename):
|
|
155
|
-
"""Sanitize filename for safe storage."""
|
|
156
|
-
# Normalize unicode
|
|
157
|
-
filename = unicodedata.normalize('NFKD', filename)
|
|
158
|
-
|
|
159
|
-
# Remove path components
|
|
160
|
-
filename = os.path.basename(filename)
|
|
161
|
-
|
|
162
|
-
# Remove null bytes
|
|
163
|
-
filename = filename.replace('\x00', '')
|
|
164
|
-
|
|
165
|
-
# Allow only safe characters
|
|
166
|
-
filename = re.sub(r'[^a-zA-Z0-9._-]', '_', filename)
|
|
167
|
-
|
|
168
|
-
# Prevent hidden files
|
|
169
|
-
filename = filename.lstrip('.')
|
|
170
|
-
|
|
171
|
-
# Limit length
|
|
172
|
-
if len(filename) > 255:
|
|
173
|
-
name, ext = os.path.splitext(filename)
|
|
174
|
-
filename = name[:255-len(ext)] + ext
|
|
175
|
-
|
|
176
|
-
return filename or 'unnamed'
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Image Validation
|
|
180
|
-
|
|
181
|
-
```python
|
|
182
|
-
from PIL import Image
|
|
183
|
-
import io
|
|
184
|
-
|
|
185
|
-
def validate_image(file_data):
|
|
186
|
-
"""Validate and reprocess image to strip metadata/payloads."""
|
|
187
|
-
try:
|
|
188
|
-
# Verify it's a valid image
|
|
189
|
-
img = Image.open(io.BytesIO(file_data))
|
|
190
|
-
img.verify()
|
|
191
|
-
|
|
192
|
-
# Reopen for processing (verify closes the file)
|
|
193
|
-
img = Image.open(io.BytesIO(file_data))
|
|
194
|
-
|
|
195
|
-
# Convert to remove potential embedded content
|
|
196
|
-
output = io.BytesIO()
|
|
197
|
-
img.save(output, format=img.format)
|
|
198
|
-
output.seek(0)
|
|
199
|
-
|
|
200
|
-
return output.read()
|
|
201
|
-
|
|
202
|
-
except Exception as e:
|
|
203
|
-
raise ValueError(f"Invalid image: {e}")
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Dangerous File Types
|
|
207
|
-
|
|
208
|
-
```python
|
|
209
|
-
# Never allow execution
|
|
210
|
-
DANGEROUS_EXTENSIONS = {
|
|
211
|
-
# Executables
|
|
212
|
-
'exe', 'dll', 'so', 'dylib', 'bin',
|
|
213
|
-
# Scripts
|
|
214
|
-
'php', 'php3', 'php4', 'php5', 'phtml',
|
|
215
|
-
'asp', 'aspx', 'ascx', 'ashx',
|
|
216
|
-
'jsp', 'jspx',
|
|
217
|
-
'cgi', 'pl', 'py', 'rb', 'sh', 'bash',
|
|
218
|
-
# Server config
|
|
219
|
-
'htaccess', 'htpasswd',
|
|
220
|
-
'config', 'ini',
|
|
221
|
-
# HTML (XSS risk)
|
|
222
|
-
'html', 'htm', 'xhtml', 'svg',
|
|
223
|
-
# Office macros
|
|
224
|
-
'docm', 'xlsm', 'pptm',
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
# Dangerous MIME types
|
|
228
|
-
DANGEROUS_MIMETYPES = {
|
|
229
|
-
'application/x-executable',
|
|
230
|
-
'application/x-msdownload',
|
|
231
|
-
'application/x-php',
|
|
232
|
-
'text/html',
|
|
233
|
-
'image/svg+xml', # Can contain scripts
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## XML External Entity (XXE) Prevention
|
|
240
|
-
|
|
241
|
-
### The Vulnerability
|
|
242
|
-
|
|
243
|
-
```xml
|
|
244
|
-
<!-- Malicious XML -->
|
|
245
|
-
<?xml version="1.0"?>
|
|
246
|
-
<!DOCTYPE foo [
|
|
247
|
-
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
|
248
|
-
]>
|
|
249
|
-
<data>&xxe;</data>
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Python Prevention
|
|
253
|
-
|
|
254
|
-
```python
|
|
255
|
-
# VULNERABLE: Default lxml settings
|
|
256
|
-
from lxml import etree
|
|
257
|
-
doc = etree.parse(untrusted_file) # XXE enabled by default
|
|
258
|
-
|
|
259
|
-
# SAFE: Disable external entities
|
|
260
|
-
from lxml import etree
|
|
261
|
-
parser = etree.XMLParser(
|
|
262
|
-
resolve_entities=False,
|
|
263
|
-
no_network=True,
|
|
264
|
-
dtd_validation=False,
|
|
265
|
-
load_dtd=False
|
|
266
|
-
)
|
|
267
|
-
doc = etree.parse(untrusted_file, parser)
|
|
268
|
-
|
|
269
|
-
# SAFE: defusedxml library (recommended)
|
|
270
|
-
import defusedxml.ElementTree as ET
|
|
271
|
-
doc = ET.parse(untrusted_file) # XXE disabled by default
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Java Prevention
|
|
275
|
-
|
|
276
|
-
```java
|
|
277
|
-
// VULNERABLE: Default DocumentBuilder
|
|
278
|
-
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
279
|
-
DocumentBuilder db = dbf.newDocumentBuilder();
|
|
280
|
-
Document doc = db.parse(untrustedFile);
|
|
281
|
-
|
|
282
|
-
// SAFE: Disable dangerous features
|
|
283
|
-
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
284
|
-
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
|
285
|
-
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
|
286
|
-
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
|
287
|
-
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
|
288
|
-
dbf.setXIncludeAware(false);
|
|
289
|
-
dbf.setExpandEntityReferences(false);
|
|
290
|
-
DocumentBuilder db = dbf.newDocumentBuilder();
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
### .NET Prevention
|
|
294
|
-
|
|
295
|
-
```csharp
|
|
296
|
-
// SAFE in .NET 4.5.2+: XmlReader is safe by default
|
|
297
|
-
XmlReader reader = XmlReader.Create(stream);
|
|
298
|
-
|
|
299
|
-
// For older versions, explicitly disable
|
|
300
|
-
XmlReaderSettings settings = new XmlReaderSettings();
|
|
301
|
-
settings.DtdProcessing = DtdProcessing.Prohibit;
|
|
302
|
-
settings.XmlResolver = null;
|
|
303
|
-
XmlReader reader = XmlReader.Create(stream, settings);
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
---
|
|
307
|
-
|
|
308
|
-
## Archive (ZIP) Handling
|
|
309
|
-
|
|
310
|
-
### Zip Slip Prevention
|
|
311
|
-
|
|
312
|
-
```python
|
|
313
|
-
import zipfile
|
|
314
|
-
import os
|
|
315
|
-
|
|
316
|
-
def safe_extract(zip_path, extract_dir):
|
|
317
|
-
"""Safely extract ZIP, preventing path traversal."""
|
|
318
|
-
extract_dir = os.path.abspath(extract_dir)
|
|
319
|
-
|
|
320
|
-
with zipfile.ZipFile(zip_path, 'r') as zf:
|
|
321
|
-
for member in zf.namelist():
|
|
322
|
-
# Get absolute path of extracted file
|
|
323
|
-
member_path = os.path.abspath(os.path.join(extract_dir, member))
|
|
324
|
-
|
|
325
|
-
# Verify it's under extract directory
|
|
326
|
-
if not member_path.startswith(extract_dir + os.sep):
|
|
327
|
-
raise ValueError(f"Path traversal in ZIP: {member}")
|
|
328
|
-
|
|
329
|
-
# Check for symlinks (additional safety)
|
|
330
|
-
if member.endswith('/'):
|
|
331
|
-
os.makedirs(member_path, exist_ok=True)
|
|
332
|
-
else:
|
|
333
|
-
os.makedirs(os.path.dirname(member_path), exist_ok=True)
|
|
334
|
-
with zf.open(member) as source, open(member_path, 'wb') as target:
|
|
335
|
-
target.write(source.read())
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
### Zip Bomb Prevention
|
|
339
|
-
|
|
340
|
-
```python
|
|
341
|
-
MAX_UNCOMPRESSED_SIZE = 100 * 1024 * 1024 # 100MB
|
|
342
|
-
MAX_COMPRESSION_RATIO = 100
|
|
343
|
-
|
|
344
|
-
def check_zip_bomb(zip_path):
|
|
345
|
-
"""Detect potential zip bombs."""
|
|
346
|
-
compressed_size = os.path.getsize(zip_path)
|
|
347
|
-
|
|
348
|
-
with zipfile.ZipFile(zip_path, 'r') as zf:
|
|
349
|
-
uncompressed_size = sum(info.file_size for info in zf.infolist())
|
|
350
|
-
|
|
351
|
-
# Check total size
|
|
352
|
-
if uncompressed_size > MAX_UNCOMPRESSED_SIZE:
|
|
353
|
-
raise ValueError(f"Uncompressed size too large: {uncompressed_size}")
|
|
354
|
-
|
|
355
|
-
# Check compression ratio
|
|
356
|
-
if compressed_size > 0:
|
|
357
|
-
ratio = uncompressed_size / compressed_size
|
|
358
|
-
if ratio > MAX_COMPRESSION_RATIO:
|
|
359
|
-
raise ValueError(f"Suspicious compression ratio: {ratio}")
|
|
360
|
-
|
|
361
|
-
return True
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
---
|
|
365
|
-
|
|
366
|
-
## File Permissions
|
|
367
|
-
|
|
368
|
-
### Secure Defaults
|
|
369
|
-
|
|
370
|
-
```python
|
|
371
|
-
import os
|
|
372
|
-
import stat
|
|
373
|
-
|
|
374
|
-
# Uploaded files: readable by app, not executable
|
|
375
|
-
def secure_file_permissions(path):
|
|
376
|
-
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) # 640
|
|
377
|
-
|
|
378
|
-
# Directories: accessible by app
|
|
379
|
-
def secure_directory_permissions(path):
|
|
380
|
-
os.chmod(path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP) # 750
|
|
381
|
-
|
|
382
|
-
# Sensitive files: only owner
|
|
383
|
-
def sensitive_file_permissions(path):
|
|
384
|
-
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR) # 600
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
### Temporary Files
|
|
388
|
-
|
|
389
|
-
```python
|
|
390
|
-
import tempfile
|
|
391
|
-
import os
|
|
392
|
-
|
|
393
|
-
# VULNERABLE: Predictable temp file
|
|
394
|
-
with open('/tmp/myapp_temp.txt', 'w') as f:
|
|
395
|
-
f.write(sensitive_data)
|
|
396
|
-
|
|
397
|
-
# SAFE: Secure temp file
|
|
398
|
-
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
|
399
|
-
f.write(sensitive_data)
|
|
400
|
-
temp_path = f.name
|
|
401
|
-
# File has restrictive permissions automatically
|
|
402
|
-
|
|
403
|
-
# SAFE: Temp directory
|
|
404
|
-
with tempfile.TemporaryDirectory() as tmpdir:
|
|
405
|
-
# Directory and contents deleted on exit
|
|
406
|
-
pass
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
---
|
|
410
|
-
|
|
411
|
-
## Grep Patterns for Detection
|
|
412
|
-
|
|
413
|
-
```bash
|
|
414
|
-
# Path traversal risks
|
|
415
|
-
grep -rn "open(.*request\|send_file(.*request" --include="*.py"
|
|
416
|
-
grep -rn "fs\.readFile.*req\|fs\.writeFile.*req" --include="*.js"
|
|
417
|
-
|
|
418
|
-
# Dangerous file operations
|
|
419
|
-
grep -rn "os\.system.*file\|subprocess.*file" --include="*.py"
|
|
420
|
-
|
|
421
|
-
# XML parsing (XXE risk)
|
|
422
|
-
grep -rn "etree\.parse\|xml\.parse\|DOM\.parse" --include="*.py" --include="*.java"
|
|
423
|
-
grep -rn "XMLReader\|DocumentBuilder" --include="*.java"
|
|
424
|
-
|
|
425
|
-
# ZIP handling
|
|
426
|
-
grep -rn "zipfile\|ZipFile\|extractall" --include="*.py" --include="*.java"
|
|
427
|
-
|
|
428
|
-
# File permissions
|
|
429
|
-
grep -rn "chmod 777\|chmod 666\|chmod 755" --include="*.py" --include="*.sh"
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
---
|
|
433
|
-
|
|
434
|
-
## Testing Checklist
|
|
435
|
-
|
|
436
|
-
- [ ] Path traversal prevented (canonicalization + validation)
|
|
437
|
-
- [ ] File extensions validated against allowlist
|
|
438
|
-
- [ ] MIME types validated (not just Content-Type header)
|
|
439
|
-
- [ ] Filenames sanitized (don't use user input directly)
|
|
440
|
-
- [ ] Files stored outside webroot
|
|
441
|
-
- [ ] Restrictive file permissions set
|
|
442
|
-
- [ ] Upload size limits enforced
|
|
443
|
-
- [ ] Dangerous file types blocked
|
|
444
|
-
- [ ] XML parsing has XXE disabled
|
|
445
|
-
- [ ] ZIP extraction validates paths
|
|
446
|
-
- [ ] ZIP bomb detection in place
|
|
447
|
-
- [ ] Temporary files handled securely
|
|
448
|
-
|
|
449
|
-
---
|
|
450
|
-
|
|
451
|
-
## References
|
|
452
|
-
|
|
453
|
-
- [OWASP File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html)
|
|
454
|
-
- [OWASP XXE Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html)
|
|
455
|
-
- [CWE-22: Path Traversal](https://cwe.mitre.org/data/definitions/22.html)
|
|
456
|
-
- [CWE-434: Unrestricted File Upload](https://cwe.mitre.org/data/definitions/434.html)
|
|
457
|
-
- [CWE-611: XXE](https://cwe.mitre.org/data/definitions/611.html)
|
|
1
|
+
# File Security Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
File operations present multiple security risks: path traversal attacks, malicious file uploads, XML External Entity (XXE) attacks, and insecure file permissions. This reference covers secure patterns for handling files.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Path Traversal Prevention
|
|
10
|
+
|
|
11
|
+
### The Vulnerability
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
# VULNERABLE: User-controlled path
|
|
15
|
+
@app.route('/download')
|
|
16
|
+
def download():
|
|
17
|
+
filename = request.args.get('file')
|
|
18
|
+
return send_file(f'/uploads/{filename}')
|
|
19
|
+
|
|
20
|
+
# Attack: ?file=../../../etc/passwd
|
|
21
|
+
# Results in: /uploads/../../../etc/passwd → /etc/passwd
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Prevention Techniques
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import os
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
# Method 1: Validate and canonicalize path
|
|
31
|
+
def safe_join(base_directory, user_path):
|
|
32
|
+
"""Safely join paths, preventing traversal."""
|
|
33
|
+
# Resolve to absolute path
|
|
34
|
+
base = Path(base_directory).resolve()
|
|
35
|
+
target = (base / user_path).resolve()
|
|
36
|
+
|
|
37
|
+
# Verify target is under base
|
|
38
|
+
if not str(target).startswith(str(base)):
|
|
39
|
+
raise ValueError("Path traversal detected")
|
|
40
|
+
|
|
41
|
+
return str(target)
|
|
42
|
+
|
|
43
|
+
# Method 2: Use allowlist of files
|
|
44
|
+
ALLOWED_FILES = {'report.pdf', 'manual.pdf', 'readme.txt'}
|
|
45
|
+
|
|
46
|
+
def download_file(filename):
|
|
47
|
+
if filename not in ALLOWED_FILES:
|
|
48
|
+
raise ValueError("File not allowed")
|
|
49
|
+
return send_file(os.path.join(UPLOAD_DIR, filename))
|
|
50
|
+
|
|
51
|
+
# Method 3: Use indirect references
|
|
52
|
+
def get_file_by_id(file_id):
|
|
53
|
+
# Map ID to filename in database
|
|
54
|
+
file_record = File.query.get(file_id)
|
|
55
|
+
if not file_record or file_record.user_id != current_user.id:
|
|
56
|
+
raise PermissionError()
|
|
57
|
+
return send_file(file_record.storage_path)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Characters to Block
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Dangerous path patterns
|
|
64
|
+
BLOCKED_PATTERNS = [
|
|
65
|
+
'..', # Parent directory
|
|
66
|
+
'~', # Home directory
|
|
67
|
+
'%2e%2e', # URL-encoded ..
|
|
68
|
+
'%252e%252e', # Double-encoded ..
|
|
69
|
+
'..\\', # Windows backslash
|
|
70
|
+
'..%5c', # URL-encoded Windows
|
|
71
|
+
'%00', # Null byte (older systems)
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
def contains_traversal(path):
|
|
75
|
+
path_lower = path.lower()
|
|
76
|
+
return any(pattern in path_lower for pattern in BLOCKED_PATTERNS)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## File Upload Security
|
|
82
|
+
|
|
83
|
+
### Defense in Depth Approach
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import magic
|
|
87
|
+
import hashlib
|
|
88
|
+
import uuid
|
|
89
|
+
from pathlib import Path
|
|
90
|
+
|
|
91
|
+
# Configuration
|
|
92
|
+
ALLOWED_EXTENSIONS = {'pdf', 'png', 'jpg', 'jpeg', 'gif'}
|
|
93
|
+
ALLOWED_MIMETYPES = {
|
|
94
|
+
'application/pdf',
|
|
95
|
+
'image/png',
|
|
96
|
+
'image/jpeg',
|
|
97
|
+
'image/gif'
|
|
98
|
+
}
|
|
99
|
+
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
|
|
100
|
+
UPLOAD_DIR = '/var/uploads' # Outside webroot
|
|
101
|
+
|
|
102
|
+
def secure_upload(file):
|
|
103
|
+
"""Comprehensive file upload validation."""
|
|
104
|
+
|
|
105
|
+
# 1. Check file size
|
|
106
|
+
file.seek(0, 2) # Seek to end
|
|
107
|
+
size = file.tell()
|
|
108
|
+
file.seek(0) # Reset
|
|
109
|
+
if size > MAX_FILE_SIZE:
|
|
110
|
+
raise ValueError(f"File too large: {size} bytes")
|
|
111
|
+
|
|
112
|
+
# 2. Validate extension
|
|
113
|
+
original_filename = file.filename
|
|
114
|
+
extension = Path(original_filename).suffix.lower().lstrip('.')
|
|
115
|
+
if extension not in ALLOWED_EXTENSIONS:
|
|
116
|
+
raise ValueError(f"Extension not allowed: {extension}")
|
|
117
|
+
|
|
118
|
+
# 3. Validate MIME type (don't trust Content-Type header)
|
|
119
|
+
mime = magic.from_buffer(file.read(2048), mime=True)
|
|
120
|
+
file.seek(0)
|
|
121
|
+
if mime not in ALLOWED_MIMETYPES:
|
|
122
|
+
raise ValueError(f"MIME type not allowed: {mime}")
|
|
123
|
+
|
|
124
|
+
# 4. Validate extension matches content
|
|
125
|
+
expected_extensions = get_extensions_for_mime(mime)
|
|
126
|
+
if extension not in expected_extensions:
|
|
127
|
+
raise ValueError("Extension doesn't match content type")
|
|
128
|
+
|
|
129
|
+
# 5. Generate safe filename (ignore user input)
|
|
130
|
+
safe_filename = f"{uuid.uuid4().hex}.{extension}"
|
|
131
|
+
|
|
132
|
+
# 6. Store outside webroot
|
|
133
|
+
storage_path = os.path.join(UPLOAD_DIR, safe_filename)
|
|
134
|
+
file.save(storage_path)
|
|
135
|
+
|
|
136
|
+
# 7. Set restrictive permissions
|
|
137
|
+
os.chmod(storage_path, 0o640)
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
'original_name': original_filename,
|
|
141
|
+
'stored_name': safe_filename,
|
|
142
|
+
'storage_path': storage_path,
|
|
143
|
+
'size': size,
|
|
144
|
+
'mime_type': mime
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Filename Sanitization
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
import re
|
|
152
|
+
import unicodedata
|
|
153
|
+
|
|
154
|
+
def sanitize_filename(filename):
|
|
155
|
+
"""Sanitize filename for safe storage."""
|
|
156
|
+
# Normalize unicode
|
|
157
|
+
filename = unicodedata.normalize('NFKD', filename)
|
|
158
|
+
|
|
159
|
+
# Remove path components
|
|
160
|
+
filename = os.path.basename(filename)
|
|
161
|
+
|
|
162
|
+
# Remove null bytes
|
|
163
|
+
filename = filename.replace('\x00', '')
|
|
164
|
+
|
|
165
|
+
# Allow only safe characters
|
|
166
|
+
filename = re.sub(r'[^a-zA-Z0-9._-]', '_', filename)
|
|
167
|
+
|
|
168
|
+
# Prevent hidden files
|
|
169
|
+
filename = filename.lstrip('.')
|
|
170
|
+
|
|
171
|
+
# Limit length
|
|
172
|
+
if len(filename) > 255:
|
|
173
|
+
name, ext = os.path.splitext(filename)
|
|
174
|
+
filename = name[:255-len(ext)] + ext
|
|
175
|
+
|
|
176
|
+
return filename or 'unnamed'
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Image Validation
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from PIL import Image
|
|
183
|
+
import io
|
|
184
|
+
|
|
185
|
+
def validate_image(file_data):
|
|
186
|
+
"""Validate and reprocess image to strip metadata/payloads."""
|
|
187
|
+
try:
|
|
188
|
+
# Verify it's a valid image
|
|
189
|
+
img = Image.open(io.BytesIO(file_data))
|
|
190
|
+
img.verify()
|
|
191
|
+
|
|
192
|
+
# Reopen for processing (verify closes the file)
|
|
193
|
+
img = Image.open(io.BytesIO(file_data))
|
|
194
|
+
|
|
195
|
+
# Convert to remove potential embedded content
|
|
196
|
+
output = io.BytesIO()
|
|
197
|
+
img.save(output, format=img.format)
|
|
198
|
+
output.seek(0)
|
|
199
|
+
|
|
200
|
+
return output.read()
|
|
201
|
+
|
|
202
|
+
except Exception as e:
|
|
203
|
+
raise ValueError(f"Invalid image: {e}")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Dangerous File Types
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
# Never allow execution
|
|
210
|
+
DANGEROUS_EXTENSIONS = {
|
|
211
|
+
# Executables
|
|
212
|
+
'exe', 'dll', 'so', 'dylib', 'bin',
|
|
213
|
+
# Scripts
|
|
214
|
+
'php', 'php3', 'php4', 'php5', 'phtml',
|
|
215
|
+
'asp', 'aspx', 'ascx', 'ashx',
|
|
216
|
+
'jsp', 'jspx',
|
|
217
|
+
'cgi', 'pl', 'py', 'rb', 'sh', 'bash',
|
|
218
|
+
# Server config
|
|
219
|
+
'htaccess', 'htpasswd',
|
|
220
|
+
'config', 'ini',
|
|
221
|
+
# HTML (XSS risk)
|
|
222
|
+
'html', 'htm', 'xhtml', 'svg',
|
|
223
|
+
# Office macros
|
|
224
|
+
'docm', 'xlsm', 'pptm',
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
# Dangerous MIME types
|
|
228
|
+
DANGEROUS_MIMETYPES = {
|
|
229
|
+
'application/x-executable',
|
|
230
|
+
'application/x-msdownload',
|
|
231
|
+
'application/x-php',
|
|
232
|
+
'text/html',
|
|
233
|
+
'image/svg+xml', # Can contain scripts
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## XML External Entity (XXE) Prevention
|
|
240
|
+
|
|
241
|
+
### The Vulnerability
|
|
242
|
+
|
|
243
|
+
```xml
|
|
244
|
+
<!-- Malicious XML -->
|
|
245
|
+
<?xml version="1.0"?>
|
|
246
|
+
<!DOCTYPE foo [
|
|
247
|
+
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
|
248
|
+
]>
|
|
249
|
+
<data>&xxe;</data>
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Python Prevention
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
# VULNERABLE: Default lxml settings
|
|
256
|
+
from lxml import etree
|
|
257
|
+
doc = etree.parse(untrusted_file) # XXE enabled by default
|
|
258
|
+
|
|
259
|
+
# SAFE: Disable external entities
|
|
260
|
+
from lxml import etree
|
|
261
|
+
parser = etree.XMLParser(
|
|
262
|
+
resolve_entities=False,
|
|
263
|
+
no_network=True,
|
|
264
|
+
dtd_validation=False,
|
|
265
|
+
load_dtd=False
|
|
266
|
+
)
|
|
267
|
+
doc = etree.parse(untrusted_file, parser)
|
|
268
|
+
|
|
269
|
+
# SAFE: defusedxml library (recommended)
|
|
270
|
+
import defusedxml.ElementTree as ET
|
|
271
|
+
doc = ET.parse(untrusted_file) # XXE disabled by default
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Java Prevention
|
|
275
|
+
|
|
276
|
+
```java
|
|
277
|
+
// VULNERABLE: Default DocumentBuilder
|
|
278
|
+
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
279
|
+
DocumentBuilder db = dbf.newDocumentBuilder();
|
|
280
|
+
Document doc = db.parse(untrustedFile);
|
|
281
|
+
|
|
282
|
+
// SAFE: Disable dangerous features
|
|
283
|
+
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
284
|
+
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
|
285
|
+
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
|
286
|
+
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
|
287
|
+
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
|
288
|
+
dbf.setXIncludeAware(false);
|
|
289
|
+
dbf.setExpandEntityReferences(false);
|
|
290
|
+
DocumentBuilder db = dbf.newDocumentBuilder();
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### .NET Prevention
|
|
294
|
+
|
|
295
|
+
```csharp
|
|
296
|
+
// SAFE in .NET 4.5.2+: XmlReader is safe by default
|
|
297
|
+
XmlReader reader = XmlReader.Create(stream);
|
|
298
|
+
|
|
299
|
+
// For older versions, explicitly disable
|
|
300
|
+
XmlReaderSettings settings = new XmlReaderSettings();
|
|
301
|
+
settings.DtdProcessing = DtdProcessing.Prohibit;
|
|
302
|
+
settings.XmlResolver = null;
|
|
303
|
+
XmlReader reader = XmlReader.Create(stream, settings);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Archive (ZIP) Handling
|
|
309
|
+
|
|
310
|
+
### Zip Slip Prevention
|
|
311
|
+
|
|
312
|
+
```python
|
|
313
|
+
import zipfile
|
|
314
|
+
import os
|
|
315
|
+
|
|
316
|
+
def safe_extract(zip_path, extract_dir):
|
|
317
|
+
"""Safely extract ZIP, preventing path traversal."""
|
|
318
|
+
extract_dir = os.path.abspath(extract_dir)
|
|
319
|
+
|
|
320
|
+
with zipfile.ZipFile(zip_path, 'r') as zf:
|
|
321
|
+
for member in zf.namelist():
|
|
322
|
+
# Get absolute path of extracted file
|
|
323
|
+
member_path = os.path.abspath(os.path.join(extract_dir, member))
|
|
324
|
+
|
|
325
|
+
# Verify it's under extract directory
|
|
326
|
+
if not member_path.startswith(extract_dir + os.sep):
|
|
327
|
+
raise ValueError(f"Path traversal in ZIP: {member}")
|
|
328
|
+
|
|
329
|
+
# Check for symlinks (additional safety)
|
|
330
|
+
if member.endswith('/'):
|
|
331
|
+
os.makedirs(member_path, exist_ok=True)
|
|
332
|
+
else:
|
|
333
|
+
os.makedirs(os.path.dirname(member_path), exist_ok=True)
|
|
334
|
+
with zf.open(member) as source, open(member_path, 'wb') as target:
|
|
335
|
+
target.write(source.read())
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Zip Bomb Prevention
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
MAX_UNCOMPRESSED_SIZE = 100 * 1024 * 1024 # 100MB
|
|
342
|
+
MAX_COMPRESSION_RATIO = 100
|
|
343
|
+
|
|
344
|
+
def check_zip_bomb(zip_path):
|
|
345
|
+
"""Detect potential zip bombs."""
|
|
346
|
+
compressed_size = os.path.getsize(zip_path)
|
|
347
|
+
|
|
348
|
+
with zipfile.ZipFile(zip_path, 'r') as zf:
|
|
349
|
+
uncompressed_size = sum(info.file_size for info in zf.infolist())
|
|
350
|
+
|
|
351
|
+
# Check total size
|
|
352
|
+
if uncompressed_size > MAX_UNCOMPRESSED_SIZE:
|
|
353
|
+
raise ValueError(f"Uncompressed size too large: {uncompressed_size}")
|
|
354
|
+
|
|
355
|
+
# Check compression ratio
|
|
356
|
+
if compressed_size > 0:
|
|
357
|
+
ratio = uncompressed_size / compressed_size
|
|
358
|
+
if ratio > MAX_COMPRESSION_RATIO:
|
|
359
|
+
raise ValueError(f"Suspicious compression ratio: {ratio}")
|
|
360
|
+
|
|
361
|
+
return True
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## File Permissions
|
|
367
|
+
|
|
368
|
+
### Secure Defaults
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
import os
|
|
372
|
+
import stat
|
|
373
|
+
|
|
374
|
+
# Uploaded files: readable by app, not executable
|
|
375
|
+
def secure_file_permissions(path):
|
|
376
|
+
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) # 640
|
|
377
|
+
|
|
378
|
+
# Directories: accessible by app
|
|
379
|
+
def secure_directory_permissions(path):
|
|
380
|
+
os.chmod(path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP) # 750
|
|
381
|
+
|
|
382
|
+
# Sensitive files: only owner
|
|
383
|
+
def sensitive_file_permissions(path):
|
|
384
|
+
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR) # 600
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Temporary Files
|
|
388
|
+
|
|
389
|
+
```python
|
|
390
|
+
import tempfile
|
|
391
|
+
import os
|
|
392
|
+
|
|
393
|
+
# VULNERABLE: Predictable temp file
|
|
394
|
+
with open('/tmp/myapp_temp.txt', 'w') as f:
|
|
395
|
+
f.write(sensitive_data)
|
|
396
|
+
|
|
397
|
+
# SAFE: Secure temp file
|
|
398
|
+
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
|
|
399
|
+
f.write(sensitive_data)
|
|
400
|
+
temp_path = f.name
|
|
401
|
+
# File has restrictive permissions automatically
|
|
402
|
+
|
|
403
|
+
# SAFE: Temp directory
|
|
404
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
405
|
+
# Directory and contents deleted on exit
|
|
406
|
+
pass
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Grep Patterns for Detection
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
# Path traversal risks
|
|
415
|
+
grep -rn "open(.*request\|send_file(.*request" --include="*.py"
|
|
416
|
+
grep -rn "fs\.readFile.*req\|fs\.writeFile.*req" --include="*.js"
|
|
417
|
+
|
|
418
|
+
# Dangerous file operations
|
|
419
|
+
grep -rn "os\.system.*file\|subprocess.*file" --include="*.py"
|
|
420
|
+
|
|
421
|
+
# XML parsing (XXE risk)
|
|
422
|
+
grep -rn "etree\.parse\|xml\.parse\|DOM\.parse" --include="*.py" --include="*.java"
|
|
423
|
+
grep -rn "XMLReader\|DocumentBuilder" --include="*.java"
|
|
424
|
+
|
|
425
|
+
# ZIP handling
|
|
426
|
+
grep -rn "zipfile\|ZipFile\|extractall" --include="*.py" --include="*.java"
|
|
427
|
+
|
|
428
|
+
# File permissions
|
|
429
|
+
grep -rn "chmod 777\|chmod 666\|chmod 755" --include="*.py" --include="*.sh"
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Testing Checklist
|
|
435
|
+
|
|
436
|
+
- [ ] Path traversal prevented (canonicalization + validation)
|
|
437
|
+
- [ ] File extensions validated against allowlist
|
|
438
|
+
- [ ] MIME types validated (not just Content-Type header)
|
|
439
|
+
- [ ] Filenames sanitized (don't use user input directly)
|
|
440
|
+
- [ ] Files stored outside webroot
|
|
441
|
+
- [ ] Restrictive file permissions set
|
|
442
|
+
- [ ] Upload size limits enforced
|
|
443
|
+
- [ ] Dangerous file types blocked
|
|
444
|
+
- [ ] XML parsing has XXE disabled
|
|
445
|
+
- [ ] ZIP extraction validates paths
|
|
446
|
+
- [ ] ZIP bomb detection in place
|
|
447
|
+
- [ ] Temporary files handled securely
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## References
|
|
452
|
+
|
|
453
|
+
- [OWASP File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html)
|
|
454
|
+
- [OWASP XXE Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html)
|
|
455
|
+
- [CWE-22: Path Traversal](https://cwe.mitre.org/data/definitions/22.html)
|
|
456
|
+
- [CWE-434: Unrestricted File Upload](https://cwe.mitre.org/data/definitions/434.html)
|
|
457
|
+
- [CWE-611: XXE](https://cwe.mitre.org/data/definitions/611.html)
|