@wazir-dev/cli 1.0.0
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/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,1765 @@
|
|
|
1
|
+
# Security Code Review
|
|
2
|
+
|
|
3
|
+
> Comprehensive guide to identifying, preventing, and remediating security
|
|
4
|
+
> vulnerabilities through systematic code review — combining manual expertise
|
|
5
|
+
> with automated tooling for defense-in-depth assurance.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Threat Landscape
|
|
10
|
+
|
|
11
|
+
### Why Security Code Review Matters
|
|
12
|
+
|
|
13
|
+
Security code review is the practice of systematically examining source code to
|
|
14
|
+
identify vulnerabilities, logic flaws, and insecure patterns before they reach
|
|
15
|
+
production. It is one of the highest-ROI security activities an organization
|
|
16
|
+
can perform.
|
|
17
|
+
|
|
18
|
+
### Cost of Catching Bugs: Review vs. Production
|
|
19
|
+
|
|
20
|
+
| Stage Detected | Relative Cost | Typical Fix Time |
|
|
21
|
+
|----------------------|---------------|------------------|
|
|
22
|
+
| Code review / PR | 1x | 30 minutes |
|
|
23
|
+
| QA / staging | 5-10x | 2-4 hours |
|
|
24
|
+
| Production (pre-breach) | 30x | 15+ hours |
|
|
25
|
+
| Post-breach | 100-680x | Weeks to months |
|
|
26
|
+
|
|
27
|
+
- A vulnerability caught in a pull request costs roughly **30 minutes** of
|
|
28
|
+
developer time with proper guidance. The same vulnerability caught in
|
|
29
|
+
post-production testing months later requires **15+ hours** of triage and
|
|
30
|
+
troubleshooting (Source: HackerOne).
|
|
31
|
+
- The average cost of a data breach in the US reached **$9.44 million** in
|
|
32
|
+
2024 (Source: IBM / Ponemon Institute).
|
|
33
|
+
- A planning-stage bug fix costs ~$100; in production, that same bug can
|
|
34
|
+
escalate to $10,000+ due to ripple effects across systems.
|
|
35
|
+
|
|
36
|
+
### Breaches Traced to Code-Level Vulnerabilities
|
|
37
|
+
|
|
38
|
+
| Incident | Year | Root Cause | Impact |
|
|
39
|
+
|-------------------------|-------|-----------------------------------|--------------------------------|
|
|
40
|
+
| Log4Shell (CVE-2021-44228) | 2021 | Unsafe JNDI lookup in logging | Millions of systems exposed |
|
|
41
|
+
| MOVEit Transfer | 2023 | SQL injection in file transfer | 2,500+ orgs, 90M+ records |
|
|
42
|
+
| US Treasury breach | 2024 | Leaked/hardcoded API key | Government systems compromised |
|
|
43
|
+
| Equifax | 2017 | Unpatched Struts deserialization | 147M records, $700M settlement |
|
|
44
|
+
| SolarWinds | 2020 | Backdoor in build pipeline | 18,000+ organizations |
|
|
45
|
+
| React Server Components | 2025 | Deserialization infinite loop | DoS on server processes |
|
|
46
|
+
|
|
47
|
+
Log4Shell remains on the list of most commonly exploited vulnerabilities
|
|
48
|
+
(position #8 as of 2025), demonstrating that code-level flaws persist for
|
|
49
|
+
years. In 2025 alone, 21,500+ CVEs were recorded in the first half of the
|
|
50
|
+
year, and attackers routinely exploit disclosed vulnerabilities within 24-48
|
|
51
|
+
hours.
|
|
52
|
+
|
|
53
|
+
### Security Bugs Commonly Missed in Review
|
|
54
|
+
|
|
55
|
+
1. **Business logic flaws** — authorization bypass via parameter manipulation
|
|
56
|
+
2. **Race conditions** — TOCTOU in file operations and financial transactions
|
|
57
|
+
3. **Second-order injection** — stored payloads triggering in different contexts
|
|
58
|
+
4. **Implicit trust** — internal service calls without authentication
|
|
59
|
+
5. **Cryptographic misuse** — correct algorithm, wrong mode or parameters
|
|
60
|
+
6. **Error information leakage** — stack traces, SQL errors in responses
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 2. Core Security Principles
|
|
65
|
+
|
|
66
|
+
### 2.1 Defense in Depth Review
|
|
67
|
+
|
|
68
|
+
Every layer of the application must independently enforce security controls.
|
|
69
|
+
A code reviewer must verify each layer, not assume upstream protection.
|
|
70
|
+
|
|
71
|
+
#### Input Validation
|
|
72
|
+
- All external inputs validated at entry points (type, length, range, format)
|
|
73
|
+
- Allowlist validation preferred over denylist
|
|
74
|
+
- Validation applied server-side regardless of client-side checks
|
|
75
|
+
- Structured data parsed with strict schemas (JSON Schema, Zod, Pydantic)
|
|
76
|
+
|
|
77
|
+
#### Output Encoding
|
|
78
|
+
- Context-appropriate encoding applied at the point of output
|
|
79
|
+
- HTML entities for HTML context, URL encoding for URLs, parameterized queries
|
|
80
|
+
for SQL
|
|
81
|
+
- Template engines configured with auto-escaping enabled by default
|
|
82
|
+
- Raw/unescaped output explicitly justified and reviewed
|
|
83
|
+
|
|
84
|
+
#### Authentication Checks
|
|
85
|
+
- Every endpoint enforcing authentication unless explicitly public
|
|
86
|
+
- Authentication middleware applied at the framework level, not per-route
|
|
87
|
+
- Token validation checking signature, expiry, issuer, and audience
|
|
88
|
+
- Credential comparison using constant-time functions
|
|
89
|
+
|
|
90
|
+
#### Authorization Checks
|
|
91
|
+
- Authorization enforced on every request, not cached from session creation
|
|
92
|
+
- Object-level authorization (IDOR prevention) for all data access
|
|
93
|
+
- Role/permission checks using centralized policy engine
|
|
94
|
+
- Principle of least privilege in service-to-service calls
|
|
95
|
+
|
|
96
|
+
### 2.2 Trust Boundary Verification
|
|
97
|
+
|
|
98
|
+
Identify where data crosses trust boundaries and verify controls at each:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
[Browser] --HTTPS--> [API Gateway] --mTLS--> [Service] --TLS--> [Database]
|
|
102
|
+
^ ^ ^ ^
|
|
103
|
+
| | | |
|
|
104
|
+
Input validation Auth + AuthZ Service auth Query params
|
|
105
|
+
CSP headers Rate limiting Input re-validation Row-level sec
|
|
106
|
+
CSRF tokens Request logging Output encoding Audit logging
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Review checklist for trust boundaries:
|
|
110
|
+
- Data re-validated when crossing from one trust zone to another
|
|
111
|
+
- No implicit trust between microservices
|
|
112
|
+
- External API responses treated as untrusted input
|
|
113
|
+
- Database query results sanitized before rendering
|
|
114
|
+
|
|
115
|
+
### 2.3 Sensitive Data Handling
|
|
116
|
+
|
|
117
|
+
- Credentials, tokens, and PII never logged or included in error messages
|
|
118
|
+
- Sensitive fields masked in serialization (`toJSON()`, `__repr__()`)
|
|
119
|
+
- Memory cleared after processing secrets (where language allows)
|
|
120
|
+
- Data classification labels applied and enforced in code
|
|
121
|
+
|
|
122
|
+
### 2.4 Cryptographic Usage Review
|
|
123
|
+
|
|
124
|
+
| Check | Secure | Insecure |
|
|
125
|
+
|--------------------------|---------------------------------|-----------------------------|
|
|
126
|
+
| Hashing passwords | bcrypt, Argon2id, scrypt | MD5, SHA-1, SHA-256 (plain) |
|
|
127
|
+
| Symmetric encryption | AES-256-GCM | AES-ECB, DES, RC4 |
|
|
128
|
+
| Asymmetric encryption | RSA-OAEP (2048+), ECDSA P-256 | RSA-PKCS1v15 (1024) |
|
|
129
|
+
| Random number generation | crypto.randomBytes, os.urandom | Math.random, random.random |
|
|
130
|
+
| Key derivation | HKDF, PBKDF2 (600k+ rounds) | PBKDF1, single-pass hash |
|
|
131
|
+
| TLS version | TLS 1.2+ with strong ciphers | SSLv3, TLS 1.0/1.1 |
|
|
132
|
+
|
|
133
|
+
### 2.5 Error Handling Review
|
|
134
|
+
|
|
135
|
+
- Exceptions caught at appropriate granularity (not blanket catch-all)
|
|
136
|
+
- Error messages safe for external consumption (no stack traces, no SQL)
|
|
137
|
+
- Failure states default to deny (fail-closed, not fail-open)
|
|
138
|
+
- Resource cleanup guaranteed (finally blocks, defer, using/with statements)
|
|
139
|
+
- Error responses consistent (same format for 401/403/404 to prevent enumeration)
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 3. Implementation Patterns
|
|
144
|
+
|
|
145
|
+
### 3.1 Security Review Process
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
149
|
+
│ Automated │ │ Manual │ │ Focused │
|
|
150
|
+
│ SAST Scan │───>│ Code Review │───>│ Threat │
|
|
151
|
+
│ (CI gate) │ │ (PR review) │ │ Assessment │
|
|
152
|
+
└──────────────┘ └──────────────┘ └──────────────┘
|
|
153
|
+
│ │ │
|
|
154
|
+
v v v
|
|
155
|
+
Block on critical Approve/Request Update threat
|
|
156
|
+
findings changes model
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Phase 1: Automated Pre-screening**
|
|
160
|
+
- SAST tools run on every PR (Semgrep, CodeQL, Bandit)
|
|
161
|
+
- Secret scanning blocks commits with credentials
|
|
162
|
+
- Dependency scanning flags known-vulnerable packages
|
|
163
|
+
- License compliance checks
|
|
164
|
+
|
|
165
|
+
**Phase 2: Manual Security Review**
|
|
166
|
+
- Triggered for security-sensitive changes (auth, crypto, input handling)
|
|
167
|
+
- Reviewer follows structured checklist (see Section 5)
|
|
168
|
+
- Focus on logic flaws that automated tools miss
|
|
169
|
+
- Business context applied to technical findings
|
|
170
|
+
|
|
171
|
+
**Phase 3: Focused Threat Assessment**
|
|
172
|
+
- For significant architectural changes
|
|
173
|
+
- Threat model updated with new attack surfaces
|
|
174
|
+
- Penetration testing scope adjusted
|
|
175
|
+
|
|
176
|
+
### 3.2 Review Focus Areas by File Type
|
|
177
|
+
|
|
178
|
+
| File Type / Pattern | Security Focus |
|
|
179
|
+
|-----------------------------|---------------------------------------------------|
|
|
180
|
+
| Route handlers / controllers | Auth, authz, input validation, rate limiting |
|
|
181
|
+
| Database queries / ORM | Injection, parameterization, access control |
|
|
182
|
+
| Template files | XSS, auto-escaping, context-aware encoding |
|
|
183
|
+
| Authentication modules | Credential handling, session management, MFA |
|
|
184
|
+
| API client code | TLS verification, credential storage, error handling|
|
|
185
|
+
| Configuration files | Secrets exposure, debug settings, CORS policy |
|
|
186
|
+
| Infrastructure as Code | Public access, encryption at rest, IAM policies |
|
|
187
|
+
| Serialization / parsing | Deserialization safety, schema validation |
|
|
188
|
+
| File I/O operations | Path traversal, symlink attacks, permission checks |
|
|
189
|
+
| Cryptographic code | Algorithm choice, key management, randomness |
|
|
190
|
+
| CI/CD pipeline definitions | Script injection, secret exposure, dependency pins |
|
|
191
|
+
|
|
192
|
+
### 3.3 Taint Analysis
|
|
193
|
+
|
|
194
|
+
Taint analysis tracks data from untrusted **sources** to sensitive **sinks**
|
|
195
|
+
through the application. During manual review, trace the data flow:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
Source (untrusted) Propagation Sink (sensitive)
|
|
199
|
+
───────────────── ─────────── ────────────────
|
|
200
|
+
req.body → variable assignment → db.query()
|
|
201
|
+
req.query → string concatenation → res.send()
|
|
202
|
+
req.headers → function parameters → exec()
|
|
203
|
+
req.files → object properties → fs.readFile()
|
|
204
|
+
process.env (user-set) → array elements → eval()
|
|
205
|
+
database results → template interpolation → redirect()
|
|
206
|
+
third-party API responses → deserialization → child_process
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Review questions for taint analysis:**
|
|
210
|
+
1. Where does this data originate? (source identification)
|
|
211
|
+
2. Is the data validated/sanitized before use? (sanitizer presence)
|
|
212
|
+
3. Does the sanitization match the sink context? (context-appropriate)
|
|
213
|
+
4. Can the sanitization be bypassed? (completeness check)
|
|
214
|
+
5. Are there indirect paths that skip sanitization? (bypass routes)
|
|
215
|
+
|
|
216
|
+
### 3.4 Dangerous Function Identification
|
|
217
|
+
|
|
218
|
+
#### JavaScript / TypeScript
|
|
219
|
+
```javascript
|
|
220
|
+
// DANGEROUS — review any usage carefully
|
|
221
|
+
eval() // Code injection
|
|
222
|
+
Function() // Code injection via constructor
|
|
223
|
+
setTimeout(string) // Implicit eval
|
|
224
|
+
setInterval(string) // Implicit eval
|
|
225
|
+
document.write() // DOM XSS
|
|
226
|
+
innerHTML // DOM XSS
|
|
227
|
+
outerHTML // DOM XSS
|
|
228
|
+
child_process.exec() // Command injection (use execFile instead)
|
|
229
|
+
vm.runInNewContext() // Sandbox escape
|
|
230
|
+
new RegExp(userInput) // ReDoS
|
|
231
|
+
require(userInput) // Arbitrary module loading
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### Python
|
|
235
|
+
```python
|
|
236
|
+
# DANGEROUS — review any usage carefully
|
|
237
|
+
eval() # Code injection
|
|
238
|
+
exec() # Code injection
|
|
239
|
+
os.system() # Command injection (use subprocess with list args)
|
|
240
|
+
subprocess.shell=True # Command injection
|
|
241
|
+
pickle.loads() # Insecure deserialization
|
|
242
|
+
yaml.load() # Use yaml.safe_load()
|
|
243
|
+
__import__(user_input) # Arbitrary module loading
|
|
244
|
+
input() (Python 2) # Evaluates expressions
|
|
245
|
+
compile() # Code injection
|
|
246
|
+
marshal.loads() # Insecure deserialization
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
#### SQL (Any Language)
|
|
250
|
+
```sql
|
|
251
|
+
-- DANGEROUS — string concatenation in queries
|
|
252
|
+
"SELECT * FROM users WHERE id = " + userId -- SQL injection
|
|
253
|
+
f"DELETE FROM orders WHERE id = {order_id}" -- SQL injection
|
|
254
|
+
`UPDATE products SET name = '${name}'` -- SQL injection
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 3.5 Framework-Specific Patterns
|
|
258
|
+
|
|
259
|
+
#### Express.js / Node.js
|
|
260
|
+
```javascript
|
|
261
|
+
// REVIEW: Is body parser size-limited?
|
|
262
|
+
app.use(express.json({ limit: '100kb' })); // Good
|
|
263
|
+
app.use(express.json()); // Missing limit — DoS risk
|
|
264
|
+
|
|
265
|
+
// REVIEW: Helmet headers applied?
|
|
266
|
+
app.use(helmet());
|
|
267
|
+
|
|
268
|
+
// REVIEW: CORS properly restricted?
|
|
269
|
+
app.use(cors({ origin: 'https://app.example.com' })); // Good
|
|
270
|
+
app.use(cors()); // Allows all — bad
|
|
271
|
+
|
|
272
|
+
// REVIEW: Rate limiting on auth endpoints?
|
|
273
|
+
app.use('/api/auth', rateLimit({ windowMs: 15*60*1000, max: 100 }));
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### Django / Flask
|
|
277
|
+
```python
|
|
278
|
+
# REVIEW: CSRF protection enabled?
|
|
279
|
+
MIDDLEWARE = ['django.middleware.csrf.CsrfViewMiddleware'] # Good
|
|
280
|
+
|
|
281
|
+
# REVIEW: Auto-escaping in templates?
|
|
282
|
+
# Django: enabled by default, review {% autoescape off %} blocks
|
|
283
|
+
# Flask/Jinja2: review | safe filter usage
|
|
284
|
+
|
|
285
|
+
# REVIEW: SQL using ORM or parameterized queries?
|
|
286
|
+
User.objects.filter(id=user_id) # Good — ORM
|
|
287
|
+
cursor.execute("SELECT * FROM users WHERE id=%s", [user_id]) # Good
|
|
288
|
+
cursor.execute(f"SELECT * FROM users WHERE id={user_id}") # BAD
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 3.6 Security PR Review Template
|
|
292
|
+
|
|
293
|
+
```markdown
|
|
294
|
+
## Security Review Checklist
|
|
295
|
+
|
|
296
|
+
### Authentication & Authorization
|
|
297
|
+
- [ ] All endpoints require authentication (or explicitly marked public)
|
|
298
|
+
- [ ] Authorization checked for the specific resource being accessed
|
|
299
|
+
- [ ] No privilege escalation paths via parameter manipulation
|
|
300
|
+
|
|
301
|
+
### Input Handling
|
|
302
|
+
- [ ] All external inputs validated (type, length, range, format)
|
|
303
|
+
- [ ] Validation occurs server-side
|
|
304
|
+
- [ ] File uploads validated (type, size, content, filename sanitized)
|
|
305
|
+
|
|
306
|
+
### Output Encoding
|
|
307
|
+
- [ ] Context-appropriate encoding applied at output points
|
|
308
|
+
- [ ] No raw HTML rendering of user-supplied data
|
|
309
|
+
- [ ] API responses do not leak internal details
|
|
310
|
+
|
|
311
|
+
### Data Protection
|
|
312
|
+
- [ ] No secrets or credentials in code, configs, or logs
|
|
313
|
+
- [ ] PII handled according to data classification policy
|
|
314
|
+
- [ ] Sensitive data encrypted in transit and at rest
|
|
315
|
+
|
|
316
|
+
### Error Handling
|
|
317
|
+
- [ ] Errors fail closed (deny by default)
|
|
318
|
+
- [ ] No sensitive data in error messages or logs
|
|
319
|
+
- [ ] Resources properly cleaned up on failure
|
|
320
|
+
|
|
321
|
+
### Dependencies
|
|
322
|
+
- [ ] No known-vulnerable dependencies introduced
|
|
323
|
+
- [ ] Dependencies pinned to specific versions
|
|
324
|
+
- [ ] New dependencies reviewed for security posture
|
|
325
|
+
|
|
326
|
+
### Reviewer Sign-off
|
|
327
|
+
- Reviewer: _______________
|
|
328
|
+
- Date: _______________
|
|
329
|
+
- Risk Level: [ ] Low [ ] Medium [ ] High [ ] Critical
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 4. Vulnerability Catalog
|
|
335
|
+
|
|
336
|
+
### 4.1 SQL Injection (CWE-89)
|
|
337
|
+
|
|
338
|
+
**Risk:** Arbitrary database queries, data exfiltration, data modification.
|
|
339
|
+
|
|
340
|
+
```javascript
|
|
341
|
+
// VULNERABLE
|
|
342
|
+
app.get('/user', (req, res) => {
|
|
343
|
+
const query = `SELECT * FROM users WHERE name = '${req.query.name}'`;
|
|
344
|
+
db.query(query); // Attacker: name=' OR '1'='1
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// SECURE
|
|
348
|
+
app.get('/user', (req, res) => {
|
|
349
|
+
db.query('SELECT * FROM users WHERE name = $1', [req.query.name]);
|
|
350
|
+
});
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### 4.2 Cross-Site Scripting — XSS (CWE-79)
|
|
354
|
+
|
|
355
|
+
**Risk:** Session hijacking, credential theft, defacement.
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
// VULNERABLE — Reflected XSS
|
|
359
|
+
app.get('/search', (req, res) => {
|
|
360
|
+
res.send(`<h1>Results for: ${req.query.q}</h1>`);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// SECURE
|
|
364
|
+
import { escape } from 'lodash';
|
|
365
|
+
app.get('/search', (req, res) => {
|
|
366
|
+
res.send(`<h1>Results for: ${escape(req.query.q)}</h1>`);
|
|
367
|
+
});
|
|
368
|
+
// Better: use a template engine with auto-escaping (React, Handlebars, etc.)
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### 4.3 Command Injection (CWE-78)
|
|
372
|
+
|
|
373
|
+
**Risk:** Arbitrary OS command execution, full server compromise.
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
# VULNERABLE
|
|
377
|
+
import os
|
|
378
|
+
def convert_image(filename):
|
|
379
|
+
os.system(f"convert {filename} output.png") # ; rm -rf /
|
|
380
|
+
|
|
381
|
+
# SECURE
|
|
382
|
+
import subprocess
|
|
383
|
+
def convert_image(filename):
|
|
384
|
+
subprocess.run(["convert", filename, "output.png"], check=True)
|
|
385
|
+
# List form prevents shell interpretation
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### 4.4 Path Traversal (CWE-22)
|
|
389
|
+
|
|
390
|
+
**Risk:** Arbitrary file read/write, configuration exposure, code execution.
|
|
391
|
+
|
|
392
|
+
```javascript
|
|
393
|
+
// VULNERABLE
|
|
394
|
+
app.get('/file', (req, res) => {
|
|
395
|
+
const filePath = path.join('/uploads', req.query.name);
|
|
396
|
+
res.sendFile(filePath); // name=../../etc/passwd
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// SECURE
|
|
400
|
+
app.get('/file', (req, res) => {
|
|
401
|
+
const basePath = path.resolve('/uploads');
|
|
402
|
+
const filePath = path.resolve('/uploads', req.query.name);
|
|
403
|
+
if (!filePath.startsWith(basePath)) {
|
|
404
|
+
return res.status(403).send('Forbidden');
|
|
405
|
+
}
|
|
406
|
+
res.sendFile(filePath);
|
|
407
|
+
});
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### 4.5 Hardcoded Secrets (CWE-798)
|
|
411
|
+
|
|
412
|
+
**Risk:** Credential exposure, unauthorized access, lateral movement.
|
|
413
|
+
|
|
414
|
+
GitGuardian's 2025 report found **23.8 million secrets** exposed on GitHub
|
|
415
|
+
in 2024 — a 25% increase over the previous year.
|
|
416
|
+
|
|
417
|
+
```python
|
|
418
|
+
# VULNERABLE
|
|
419
|
+
API_KEY = "sk-live-4eC39HqLyjWDarjtT1zdp7dc"
|
|
420
|
+
db_password = "super_secret_password_123"
|
|
421
|
+
|
|
422
|
+
# SECURE
|
|
423
|
+
import os
|
|
424
|
+
API_KEY = os.environ["API_KEY"]
|
|
425
|
+
db_password = os.environ["DB_PASSWORD"]
|
|
426
|
+
# Or use a secrets manager: AWS Secrets Manager, HashiCorp Vault, etc.
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 4.6 Insecure Deserialization (CWE-502)
|
|
430
|
+
|
|
431
|
+
**Risk:** Remote code execution, DoS, privilege escalation.
|
|
432
|
+
|
|
433
|
+
```python
|
|
434
|
+
# VULNERABLE
|
|
435
|
+
import pickle
|
|
436
|
+
def load_session(data):
|
|
437
|
+
return pickle.loads(base64.b64decode(data)) # RCE via crafted payload
|
|
438
|
+
|
|
439
|
+
# SECURE
|
|
440
|
+
import json
|
|
441
|
+
def load_session(data):
|
|
442
|
+
return json.loads(base64.b64decode(data)) # JSON is data-only
|
|
443
|
+
# If complex objects needed, use schema validation after parsing
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
```java
|
|
447
|
+
// VULNERABLE — Java deserialization
|
|
448
|
+
ObjectInputStream ois = new ObjectInputStream(inputStream);
|
|
449
|
+
Object obj = ois.readObject(); // Gadget chain RCE
|
|
450
|
+
|
|
451
|
+
// SECURE — Use allowlist-based deserialization filter (Java 9+)
|
|
452
|
+
ObjectInputFilter filter = ObjectInputFilter.Config
|
|
453
|
+
.createFilter("com.example.safe.*;!*");
|
|
454
|
+
ois.setObjectInputFilter(filter);
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### 4.7 Race Conditions / TOCTOU (CWE-367)
|
|
458
|
+
|
|
459
|
+
**Risk:** Double-spending, privilege escalation, data corruption.
|
|
460
|
+
|
|
461
|
+
```python
|
|
462
|
+
# VULNERABLE — Time-of-Check-to-Time-of-Use
|
|
463
|
+
import os
|
|
464
|
+
def safe_delete(filepath):
|
|
465
|
+
if os.path.isfile(filepath): # Check
|
|
466
|
+
# Attacker replaces file with symlink here
|
|
467
|
+
os.remove(filepath) # Use — may delete wrong file
|
|
468
|
+
|
|
469
|
+
# SECURE — Use atomic operations or locks
|
|
470
|
+
import fcntl
|
|
471
|
+
def safe_delete(filepath):
|
|
472
|
+
fd = os.open(filepath, os.O_RDONLY | os.O_NOFOLLOW)
|
|
473
|
+
try:
|
|
474
|
+
fcntl.flock(fd, fcntl.LOCK_EX)
|
|
475
|
+
os.unlink(filepath)
|
|
476
|
+
finally:
|
|
477
|
+
os.close(fd)
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
```javascript
|
|
481
|
+
// VULNERABLE — Balance race condition
|
|
482
|
+
async function transfer(from, to, amount) {
|
|
483
|
+
const balance = await getBalance(from);
|
|
484
|
+
if (balance >= amount) {
|
|
485
|
+
// Concurrent request can pass this check before deduction
|
|
486
|
+
await deduct(from, amount);
|
|
487
|
+
await credit(to, amount);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// SECURE — Use database transaction with row locking
|
|
492
|
+
async function transfer(from, to, amount) {
|
|
493
|
+
await db.transaction(async (trx) => {
|
|
494
|
+
const { balance } = await trx('accounts')
|
|
495
|
+
.where({ id: from })
|
|
496
|
+
.forUpdate() // Row-level lock
|
|
497
|
+
.first();
|
|
498
|
+
if (balance < amount) throw new Error('Insufficient funds');
|
|
499
|
+
await trx('accounts').where({ id: from }).decrement('balance', amount);
|
|
500
|
+
await trx('accounts').where({ id: to }).increment('balance', amount);
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### 4.8 Server-Side Request Forgery — SSRF (CWE-918)
|
|
506
|
+
|
|
507
|
+
**Risk:** Internal network scanning, cloud metadata theft, service exploitation.
|
|
508
|
+
|
|
509
|
+
```python
|
|
510
|
+
# VULNERABLE
|
|
511
|
+
import requests
|
|
512
|
+
def fetch_url(url):
|
|
513
|
+
return requests.get(url).text # url=http://169.254.169.254/latest/meta-data/
|
|
514
|
+
|
|
515
|
+
# SECURE
|
|
516
|
+
from urllib.parse import urlparse
|
|
517
|
+
import ipaddress
|
|
518
|
+
|
|
519
|
+
BLOCKED_NETWORKS = [
|
|
520
|
+
ipaddress.ip_network('10.0.0.0/8'),
|
|
521
|
+
ipaddress.ip_network('172.16.0.0/12'),
|
|
522
|
+
ipaddress.ip_network('192.168.0.0/16'),
|
|
523
|
+
ipaddress.ip_network('169.254.0.0/16'),
|
|
524
|
+
ipaddress.ip_network('127.0.0.0/8'),
|
|
525
|
+
]
|
|
526
|
+
|
|
527
|
+
def fetch_url(url):
|
|
528
|
+
parsed = urlparse(url)
|
|
529
|
+
if parsed.scheme not in ('http', 'https'):
|
|
530
|
+
raise ValueError("Invalid scheme")
|
|
531
|
+
ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname))
|
|
532
|
+
if any(ip in net for net in BLOCKED_NETWORKS):
|
|
533
|
+
raise ValueError("Blocked address")
|
|
534
|
+
return requests.get(url, allow_redirects=False, timeout=5).text
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### 4.9 Broken Access Control — IDOR (CWE-639)
|
|
538
|
+
|
|
539
|
+
**Risk:** Unauthorized data access, data modification, privilege escalation.
|
|
540
|
+
|
|
541
|
+
```javascript
|
|
542
|
+
// VULNERABLE — No ownership check
|
|
543
|
+
app.get('/api/orders/:id', auth, async (req, res) => {
|
|
544
|
+
const order = await Order.findById(req.params.id);
|
|
545
|
+
res.json(order); // Any authenticated user can access any order
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
// SECURE — Ownership verified
|
|
549
|
+
app.get('/api/orders/:id', auth, async (req, res) => {
|
|
550
|
+
const order = await Order.findOne({
|
|
551
|
+
_id: req.params.id,
|
|
552
|
+
userId: req.user.id // Scoped to authenticated user
|
|
553
|
+
});
|
|
554
|
+
if (!order) return res.status(404).json({ error: 'Not found' });
|
|
555
|
+
res.json(order);
|
|
556
|
+
});
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### 4.10 Mass Assignment (CWE-915)
|
|
560
|
+
|
|
561
|
+
**Risk:** Privilege escalation, data tampering.
|
|
562
|
+
|
|
563
|
+
```javascript
|
|
564
|
+
// VULNERABLE
|
|
565
|
+
app.put('/api/profile', auth, async (req, res) => {
|
|
566
|
+
await User.findByIdAndUpdate(req.user.id, req.body);
|
|
567
|
+
// Attacker sends: { "role": "admin", "name": "attacker" }
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
// SECURE — Allowlist fields
|
|
571
|
+
app.put('/api/profile', auth, async (req, res) => {
|
|
572
|
+
const { name, email, avatar } = req.body; // Only allowed fields
|
|
573
|
+
await User.findByIdAndUpdate(req.user.id, { name, email, avatar });
|
|
574
|
+
});
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### 4.11 Insufficient Logging (CWE-778)
|
|
578
|
+
|
|
579
|
+
**Risk:** Undetected breaches, failed forensic analysis, compliance violations.
|
|
580
|
+
|
|
581
|
+
```python
|
|
582
|
+
# VULNERABLE — No security logging
|
|
583
|
+
def login(username, password):
|
|
584
|
+
user = db.get_user(username)
|
|
585
|
+
if not verify_password(password, user.hash):
|
|
586
|
+
return {"error": "Invalid credentials"} # Silent failure
|
|
587
|
+
|
|
588
|
+
# SECURE — Security event logging
|
|
589
|
+
import logging
|
|
590
|
+
security_log = logging.getLogger("security")
|
|
591
|
+
|
|
592
|
+
def login(username, password):
|
|
593
|
+
user = db.get_user(username)
|
|
594
|
+
if not verify_password(password, user.hash):
|
|
595
|
+
security_log.warning(
|
|
596
|
+
"auth.failure",
|
|
597
|
+
extra={
|
|
598
|
+
"username": username,
|
|
599
|
+
"ip": request.remote_addr,
|
|
600
|
+
"user_agent": request.headers.get("User-Agent"),
|
|
601
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
602
|
+
}
|
|
603
|
+
)
|
|
604
|
+
return {"error": "Invalid credentials"}
|
|
605
|
+
security_log.info("auth.success", extra={"username": username})
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### 4.12 XML External Entity — XXE (CWE-611)
|
|
609
|
+
|
|
610
|
+
**Risk:** File disclosure, SSRF, DoS.
|
|
611
|
+
|
|
612
|
+
```python
|
|
613
|
+
# VULNERABLE
|
|
614
|
+
from lxml import etree
|
|
615
|
+
def parse_xml(data):
|
|
616
|
+
return etree.fromstring(data) # Processes external entities
|
|
617
|
+
|
|
618
|
+
# SECURE
|
|
619
|
+
from defusedxml import ElementTree
|
|
620
|
+
def parse_xml(data):
|
|
621
|
+
return ElementTree.fromstring(data) # External entities disabled
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### 4.13 Open Redirect (CWE-601)
|
|
625
|
+
|
|
626
|
+
**Risk:** Phishing, credential theft, trust exploitation.
|
|
627
|
+
|
|
628
|
+
```javascript
|
|
629
|
+
// VULNERABLE
|
|
630
|
+
app.get('/redirect', (req, res) => {
|
|
631
|
+
res.redirect(req.query.url); // url=https://evil.com/fake-login
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
// SECURE
|
|
635
|
+
const ALLOWED_HOSTS = ['app.example.com', 'docs.example.com'];
|
|
636
|
+
app.get('/redirect', (req, res) => {
|
|
637
|
+
const url = new URL(req.query.url, 'https://app.example.com');
|
|
638
|
+
if (!ALLOWED_HOSTS.includes(url.hostname)) {
|
|
639
|
+
return res.status(400).send('Invalid redirect');
|
|
640
|
+
}
|
|
641
|
+
res.redirect(url.toString());
|
|
642
|
+
});
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### 4.14 Prototype Pollution (CWE-1321)
|
|
646
|
+
|
|
647
|
+
**Risk:** Property injection, DoS, RCE in Node.js applications.
|
|
648
|
+
|
|
649
|
+
```javascript
|
|
650
|
+
// VULNERABLE
|
|
651
|
+
function merge(target, source) {
|
|
652
|
+
for (const key in source) {
|
|
653
|
+
if (typeof source[key] === 'object') {
|
|
654
|
+
target[key] = merge(target[key] || {}, source[key]);
|
|
655
|
+
} else {
|
|
656
|
+
target[key] = source[key];
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return target;
|
|
660
|
+
}
|
|
661
|
+
// Attacker: {"__proto__": {"isAdmin": true}}
|
|
662
|
+
|
|
663
|
+
// SECURE
|
|
664
|
+
function safeMerge(target, source) {
|
|
665
|
+
for (const key of Object.keys(source)) { // Own properties only
|
|
666
|
+
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
667
|
+
continue; // Skip dangerous keys
|
|
668
|
+
}
|
|
669
|
+
if (typeof source[key] === 'object' && source[key] !== null) {
|
|
670
|
+
target[key] = safeMerge(target[key] || {}, source[key]);
|
|
671
|
+
} else {
|
|
672
|
+
target[key] = source[key];
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return target;
|
|
676
|
+
}
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### 4.15 Regex Denial of Service — ReDoS (CWE-1333)
|
|
680
|
+
|
|
681
|
+
**Risk:** Application DoS via catastrophic backtracking.
|
|
682
|
+
|
|
683
|
+
```javascript
|
|
684
|
+
// VULNERABLE — Catastrophic backtracking
|
|
685
|
+
const EMAIL_REGEX = /^([a-zA-Z0-9]+)+@example\.com$/;
|
|
686
|
+
// Input: "aaaaaaaaaaaaaaaaaaaaaaaaaaaa!" causes exponential time
|
|
687
|
+
|
|
688
|
+
// SECURE — Use linear-time patterns or RE2
|
|
689
|
+
const EMAIL_REGEX = /^[a-zA-Z0-9]+@example\.com$/; // No nested quantifiers
|
|
690
|
+
// Or use Google's RE2 engine which guarantees linear time
|
|
691
|
+
import RE2 from 're2';
|
|
692
|
+
const pattern = new RE2('^[a-zA-Z0-9]+@example\\.com$');
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### 4.16 Insecure Randomness (CWE-330)
|
|
696
|
+
|
|
697
|
+
```javascript
|
|
698
|
+
// VULNERABLE
|
|
699
|
+
const token = Math.random().toString(36).substring(2); // Predictable
|
|
700
|
+
|
|
701
|
+
// SECURE
|
|
702
|
+
import crypto from 'crypto';
|
|
703
|
+
const token = crypto.randomBytes(32).toString('hex');
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### 4.17 Missing Security Headers
|
|
707
|
+
|
|
708
|
+
```javascript
|
|
709
|
+
// VULNERABLE — No security headers
|
|
710
|
+
app.get('/', (req, res) => res.send(html));
|
|
711
|
+
|
|
712
|
+
// SECURE — Using Helmet.js
|
|
713
|
+
import helmet from 'helmet';
|
|
714
|
+
app.use(helmet({
|
|
715
|
+
contentSecurityPolicy: {
|
|
716
|
+
directives: {
|
|
717
|
+
defaultSrc: ["'self'"],
|
|
718
|
+
scriptSrc: ["'self'"],
|
|
719
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
720
|
+
imgSrc: ["'self'", "data:"],
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
|
|
724
|
+
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
|
|
725
|
+
}));
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
---
|
|
729
|
+
|
|
730
|
+
## 5. Security Checklist
|
|
731
|
+
|
|
732
|
+
### Input Validation (7 items)
|
|
733
|
+
- [ ] All external inputs validated for type, length, range, and format
|
|
734
|
+
- [ ] Server-side validation present regardless of client-side checks
|
|
735
|
+
- [ ] Allowlist validation used over denylist where possible
|
|
736
|
+
- [ ] File uploads validated: type, size, content sniffing, filename sanitized
|
|
737
|
+
- [ ] JSON/XML/YAML parsing uses safe parsers with strict schemas
|
|
738
|
+
- [ ] Regular expressions reviewed for ReDoS (no nested quantifiers)
|
|
739
|
+
- [ ] URL inputs validated against SSRF (block internal/metadata addresses)
|
|
740
|
+
|
|
741
|
+
### Authentication (5 items)
|
|
742
|
+
- [ ] All non-public endpoints require authentication
|
|
743
|
+
- [ ] Password hashing uses bcrypt/Argon2id with appropriate cost factor
|
|
744
|
+
- [ ] Multi-factor authentication available for sensitive operations
|
|
745
|
+
- [ ] Account lockout or rate limiting on authentication endpoints
|
|
746
|
+
- [ ] Session tokens generated with cryptographic randomness
|
|
747
|
+
|
|
748
|
+
### Authorization (5 items)
|
|
749
|
+
- [ ] Authorization checked on every request (not cached from login)
|
|
750
|
+
- [ ] Object-level authorization prevents IDOR on all data endpoints
|
|
751
|
+
- [ ] Function-level authorization prevents privilege escalation
|
|
752
|
+
- [ ] Mass assignment prevented (allowlist of modifiable fields)
|
|
753
|
+
- [ ] Default deny — new endpoints require explicit authorization rules
|
|
754
|
+
|
|
755
|
+
### Cryptography (4 items)
|
|
756
|
+
- [ ] No deprecated algorithms (MD5, SHA-1, DES, RC4, ECB mode)
|
|
757
|
+
- [ ] Keys and secrets stored in environment variables or secrets manager
|
|
758
|
+
- [ ] Random values generated using cryptographic RNG
|
|
759
|
+
- [ ] TLS 1.2+ enforced for all external communications
|
|
760
|
+
|
|
761
|
+
### Error Handling (4 items)
|
|
762
|
+
- [ ] Errors fail closed (deny access on failure)
|
|
763
|
+
- [ ] No stack traces, SQL errors, or internal paths in responses
|
|
764
|
+
- [ ] Error responses consistent across 401/403/404 (prevent enumeration)
|
|
765
|
+
- [ ] Resources cleaned up in all error paths (connections, file handles)
|
|
766
|
+
|
|
767
|
+
### Logging & Monitoring (4 items)
|
|
768
|
+
- [ ] Authentication failures logged with IP, timestamp, user agent
|
|
769
|
+
- [ ] Authorization failures logged with resource and principal
|
|
770
|
+
- [ ] No sensitive data (passwords, tokens, PII) in log output
|
|
771
|
+
- [ ] Tampering attempts logged (input validation failures, CSRF mismatches)
|
|
772
|
+
|
|
773
|
+
### Data Protection (4 items)
|
|
774
|
+
- [ ] No hardcoded secrets, API keys, or passwords in source code
|
|
775
|
+
- [ ] PII encrypted at rest and masked in logs
|
|
776
|
+
- [ ] Sensitive data cleared from memory after use (where applicable)
|
|
777
|
+
- [ ] HTTP responses include appropriate cache-control for sensitive data
|
|
778
|
+
|
|
779
|
+
### Dependencies (3 items)
|
|
780
|
+
- [ ] No known-vulnerable dependencies (checked via npm audit, pip-audit, etc.)
|
|
781
|
+
- [ ] Dependencies pinned to specific versions (lockfile committed)
|
|
782
|
+
- [ ] New dependencies reviewed for maintainer reputation and security history
|
|
783
|
+
|
|
784
|
+
---
|
|
785
|
+
|
|
786
|
+
## 6. Tools & Automation
|
|
787
|
+
|
|
788
|
+
### 6.1 Semgrep
|
|
789
|
+
|
|
790
|
+
Semgrep is an open-source static analysis tool supporting 30+ languages
|
|
791
|
+
with a pattern-matching approach that makes custom rules straightforward
|
|
792
|
+
to write.
|
|
793
|
+
|
|
794
|
+
**Installation and basic usage:**
|
|
795
|
+
```bash
|
|
796
|
+
# Install
|
|
797
|
+
pip install semgrep
|
|
798
|
+
|
|
799
|
+
# Run with community rules
|
|
800
|
+
semgrep --config=auto .
|
|
801
|
+
|
|
802
|
+
# Run specific security rulesets
|
|
803
|
+
semgrep --config=p/security-audit .
|
|
804
|
+
semgrep --config=p/owasp-top-ten .
|
|
805
|
+
semgrep --config=p/javascript .
|
|
806
|
+
|
|
807
|
+
# Run with custom rules
|
|
808
|
+
semgrep --config=.semgrep/ .
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
**Custom Semgrep rule — Detect missing auth decorator (Python/Flask):**
|
|
812
|
+
```yaml
|
|
813
|
+
rules:
|
|
814
|
+
- id: flask-route-missing-auth
|
|
815
|
+
patterns:
|
|
816
|
+
- pattern: |
|
|
817
|
+
@app.route(...)
|
|
818
|
+
def $FUNC(...):
|
|
819
|
+
...
|
|
820
|
+
- pattern-not: |
|
|
821
|
+
@login_required
|
|
822
|
+
@app.route(...)
|
|
823
|
+
def $FUNC(...):
|
|
824
|
+
...
|
|
825
|
+
- pattern-not: |
|
|
826
|
+
@app.route(...)
|
|
827
|
+
@login_required
|
|
828
|
+
def $FUNC(...):
|
|
829
|
+
...
|
|
830
|
+
message: "Route $FUNC is missing @login_required decorator"
|
|
831
|
+
severity: WARNING
|
|
832
|
+
languages: [python]
|
|
833
|
+
metadata:
|
|
834
|
+
category: security
|
|
835
|
+
cwe: CWE-306
|
|
836
|
+
owasp: A01:2021 Broken Access Control
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
**Custom Semgrep rule — Detect SQL injection (JavaScript):**
|
|
840
|
+
```yaml
|
|
841
|
+
rules:
|
|
842
|
+
- id: node-sql-injection
|
|
843
|
+
patterns:
|
|
844
|
+
- pattern-either:
|
|
845
|
+
- pattern: $DB.query(`...${$INPUT}...`)
|
|
846
|
+
- pattern: $DB.query("..." + $INPUT + "...")
|
|
847
|
+
- pattern: $DB.query(`...` + $INPUT)
|
|
848
|
+
message: |
|
|
849
|
+
Potential SQL injection. Use parameterized queries instead of
|
|
850
|
+
string interpolation: $DB.query('SELECT ... WHERE id = $1', [$INPUT])
|
|
851
|
+
severity: ERROR
|
|
852
|
+
languages: [javascript, typescript]
|
|
853
|
+
metadata:
|
|
854
|
+
cwe: CWE-89
|
|
855
|
+
owasp: A03:2021 Injection
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
**Custom Semgrep rule — Detect hardcoded secrets:**
|
|
859
|
+
```yaml
|
|
860
|
+
rules:
|
|
861
|
+
- id: hardcoded-secret
|
|
862
|
+
patterns:
|
|
863
|
+
- pattern-either:
|
|
864
|
+
- pattern: $KEY = "...AKIA..."
|
|
865
|
+
- pattern: $KEY = "sk-live-..."
|
|
866
|
+
- pattern: $KEY = "ghp_..."
|
|
867
|
+
- pattern: $KEY = "glpat-..."
|
|
868
|
+
- metavariable-regex:
|
|
869
|
+
metavariable: $KEY
|
|
870
|
+
regex: (?i)(api_key|secret|token|password|credential)
|
|
871
|
+
message: "Hardcoded secret detected in $KEY"
|
|
872
|
+
severity: ERROR
|
|
873
|
+
languages: [python, javascript, typescript, java, go]
|
|
874
|
+
metadata:
|
|
875
|
+
cwe: CWE-798
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
**CI/CD integration (GitHub Actions):**
|
|
879
|
+
```yaml
|
|
880
|
+
# .github/workflows/semgrep.yml
|
|
881
|
+
name: Semgrep Security Scan
|
|
882
|
+
on: [pull_request]
|
|
883
|
+
jobs:
|
|
884
|
+
semgrep:
|
|
885
|
+
runs-on: ubuntu-latest
|
|
886
|
+
steps:
|
|
887
|
+
- uses: actions/checkout@v4
|
|
888
|
+
- uses: semgrep/semgrep-action@v1
|
|
889
|
+
with:
|
|
890
|
+
config: >-
|
|
891
|
+
p/security-audit
|
|
892
|
+
p/owasp-top-ten
|
|
893
|
+
.semgrep/
|
|
894
|
+
env:
|
|
895
|
+
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
### 6.2 CodeQL
|
|
899
|
+
|
|
900
|
+
CodeQL treats code as data, building a relational database from source
|
|
901
|
+
code that can be queried for vulnerability patterns. Over **400 CVEs**
|
|
902
|
+
have been identified using CodeQL variant analysis.
|
|
903
|
+
|
|
904
|
+
**GitHub Actions setup:**
|
|
905
|
+
```yaml
|
|
906
|
+
# .github/workflows/codeql.yml
|
|
907
|
+
name: CodeQL Analysis
|
|
908
|
+
on:
|
|
909
|
+
push:
|
|
910
|
+
branches: [main]
|
|
911
|
+
pull_request:
|
|
912
|
+
branches: [main]
|
|
913
|
+
schedule:
|
|
914
|
+
- cron: '0 6 * * 1' # Weekly Monday scan
|
|
915
|
+
jobs:
|
|
916
|
+
analyze:
|
|
917
|
+
runs-on: ubuntu-latest
|
|
918
|
+
permissions:
|
|
919
|
+
security-events: write
|
|
920
|
+
strategy:
|
|
921
|
+
matrix:
|
|
922
|
+
language: ['javascript', 'python']
|
|
923
|
+
steps:
|
|
924
|
+
- uses: actions/checkout@v4
|
|
925
|
+
- uses: github/codeql-action/init@v3
|
|
926
|
+
with:
|
|
927
|
+
languages: ${{ matrix.language }}
|
|
928
|
+
queries: security-extended
|
|
929
|
+
- uses: github/codeql-action/analyze@v3
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
**Custom CodeQL query — Find unvalidated redirects (JavaScript):**
|
|
933
|
+
```ql
|
|
934
|
+
/**
|
|
935
|
+
* @name Unvalidated URL redirect
|
|
936
|
+
* @description Finds redirects using user-controlled URLs without validation
|
|
937
|
+
* @kind path-problem
|
|
938
|
+
* @problem.severity error
|
|
939
|
+
* @security-severity 6.1
|
|
940
|
+
* @id js/unvalidated-redirect
|
|
941
|
+
* @tags security
|
|
942
|
+
*/
|
|
943
|
+
|
|
944
|
+
import javascript
|
|
945
|
+
import semmle.javascript.security.dataflow.ServerSideUrlRedirectQuery
|
|
946
|
+
|
|
947
|
+
from ServerSideUrlRedirect::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
|
948
|
+
where cfg.hasFlowPath(source, sink)
|
|
949
|
+
select sink.getNode(), source, sink, "Untrusted URL redirection from $@.", source.getNode(),
|
|
950
|
+
"user input"
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
### 6.3 SonarQube
|
|
954
|
+
|
|
955
|
+
```bash
|
|
956
|
+
# Docker setup for local scanning
|
|
957
|
+
docker run -d --name sonarqube -p 9000:9000 sonarqube:community
|
|
958
|
+
|
|
959
|
+
# Scan a project
|
|
960
|
+
sonar-scanner \
|
|
961
|
+
-Dsonar.projectKey=myapp \
|
|
962
|
+
-Dsonar.sources=src \
|
|
963
|
+
-Dsonar.host.url=http://localhost:9000 \
|
|
964
|
+
-Dsonar.token=$SONAR_TOKEN \
|
|
965
|
+
-Dsonar.qualitygate.wait=true
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
**Quality gate configuration for security:**
|
|
969
|
+
- 0 blocker issues (critical vulnerabilities)
|
|
970
|
+
- 0 critical issues (high-severity vulnerabilities)
|
|
971
|
+
- Security rating must be A
|
|
972
|
+
- Security hotspots reviewed > 80%
|
|
973
|
+
|
|
974
|
+
### 6.4 Bandit (Python)
|
|
975
|
+
|
|
976
|
+
```bash
|
|
977
|
+
# Install and run
|
|
978
|
+
pip install bandit
|
|
979
|
+
|
|
980
|
+
# Scan a project
|
|
981
|
+
bandit -r ./src -f json -o bandit-report.json
|
|
982
|
+
|
|
983
|
+
# With configuration
|
|
984
|
+
bandit -r ./src -c .bandit.yml -ll # Only medium+ severity
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
**Configuration file (.bandit.yml):**
|
|
988
|
+
```yaml
|
|
989
|
+
# .bandit.yml
|
|
990
|
+
skips:
|
|
991
|
+
- B101 # assert_used (acceptable in tests)
|
|
992
|
+
exclude_dirs:
|
|
993
|
+
- tests
|
|
994
|
+
- venv
|
|
995
|
+
tests:
|
|
996
|
+
- B301 # pickle
|
|
997
|
+
- B302 # marshal
|
|
998
|
+
- B303 # insecure hash (MD5, SHA1)
|
|
999
|
+
- B304 # insecure cipher (DES)
|
|
1000
|
+
- B305 # insecure cipher mode
|
|
1001
|
+
- B306 # mktemp
|
|
1002
|
+
- B307 # eval
|
|
1003
|
+
- B308 # mark_safe (Django)
|
|
1004
|
+
- B601 # paramiko shell
|
|
1005
|
+
- B602 # subprocess with shell=True
|
|
1006
|
+
- B608 # SQL injection
|
|
1007
|
+
- B703 # Django mark_safe XSS
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
### 6.5 ESLint Security Plugins
|
|
1011
|
+
|
|
1012
|
+
```bash
|
|
1013
|
+
# Install security plugins
|
|
1014
|
+
npm install --save-dev eslint-plugin-security eslint-plugin-no-unsanitized
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
```javascript
|
|
1018
|
+
// eslint.config.js (flat config)
|
|
1019
|
+
import security from 'eslint-plugin-security';
|
|
1020
|
+
import noUnsanitized from 'eslint-plugin-no-unsanitized';
|
|
1021
|
+
|
|
1022
|
+
export default [
|
|
1023
|
+
{
|
|
1024
|
+
plugins: { security, 'no-unsanitized': noUnsanitized },
|
|
1025
|
+
rules: {
|
|
1026
|
+
'security/detect-eval-with-expression': 'error',
|
|
1027
|
+
'security/detect-non-literal-fs-filename': 'warn',
|
|
1028
|
+
'security/detect-non-literal-regexp': 'warn',
|
|
1029
|
+
'security/detect-non-literal-require': 'error',
|
|
1030
|
+
'security/detect-object-injection': 'warn',
|
|
1031
|
+
'security/detect-possible-timing-attacks': 'error',
|
|
1032
|
+
'security/detect-child-process': 'warn',
|
|
1033
|
+
'no-unsanitized/method': 'error',
|
|
1034
|
+
'no-unsanitized/property': 'error',
|
|
1035
|
+
},
|
|
1036
|
+
},
|
|
1037
|
+
];
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
### 6.6 GitHub Advanced Security
|
|
1041
|
+
|
|
1042
|
+
GitHub Advanced Security provides three integrated capabilities:
|
|
1043
|
+
|
|
1044
|
+
1. **Code scanning** — CodeQL-powered SAST on every PR
|
|
1045
|
+
2. **Secret scanning** — Detects 200+ secret patterns in commits
|
|
1046
|
+
3. **Dependency review** — Flags vulnerable dependencies in PRs
|
|
1047
|
+
|
|
1048
|
+
```yaml
|
|
1049
|
+
# Enable secret scanning push protection
|
|
1050
|
+
# In repository Settings > Code security and analysis
|
|
1051
|
+
# Secret scanning: Enabled
|
|
1052
|
+
# Push protection: Enabled
|
|
1053
|
+
|
|
1054
|
+
# Dependency review action
|
|
1055
|
+
- uses: actions/dependency-review-action@v4
|
|
1056
|
+
with:
|
|
1057
|
+
fail-on-severity: moderate
|
|
1058
|
+
deny-licenses: GPL-3.0, AGPL-3.0
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
### 6.7 Snyk Code
|
|
1062
|
+
|
|
1063
|
+
```bash
|
|
1064
|
+
# Install and authenticate
|
|
1065
|
+
npm install -g snyk
|
|
1066
|
+
snyk auth
|
|
1067
|
+
|
|
1068
|
+
# Test for vulnerabilities
|
|
1069
|
+
snyk code test # SAST scan
|
|
1070
|
+
snyk test # Dependency scan
|
|
1071
|
+
snyk container test # Container scan
|
|
1072
|
+
snyk iac test # IaC scan
|
|
1073
|
+
|
|
1074
|
+
# Monitor in CI
|
|
1075
|
+
snyk monitor --all-projects
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
### 6.8 Tool Comparison Matrix
|
|
1079
|
+
|
|
1080
|
+
| Tool | Type | Languages | CI Integration | Custom Rules | Cost |
|
|
1081
|
+
|---------------|-------------|---------------|----------------|--------------|------------|
|
|
1082
|
+
| Semgrep | SAST | 30+ | Native | YAML (easy) | Free/Paid |
|
|
1083
|
+
| CodeQL | SAST | 12 | GitHub Actions | QL (moderate)| Free (OSS) |
|
|
1084
|
+
| SonarQube | SAST + Lint | 30+ | Plugin-based | Java (hard) | Free/Paid |
|
|
1085
|
+
| Bandit | SAST | Python only | Any CI | Python | Free |
|
|
1086
|
+
| ESLint-security| Lint | JS/TS only | Any CI | JS (easy) | Free |
|
|
1087
|
+
| Snyk Code | SAST + SCA | 10+ | Native | Limited | Free/Paid |
|
|
1088
|
+
| GitHub GHAS | SAST + SCA | 12 (CodeQL) | Native | QL | Paid |
|
|
1089
|
+
|
|
1090
|
+
---
|
|
1091
|
+
|
|
1092
|
+
## 7. Platform-Specific Guidance
|
|
1093
|
+
|
|
1094
|
+
### 7.1 TypeScript / Node.js
|
|
1095
|
+
|
|
1096
|
+
**Common vulnerability patterns:**
|
|
1097
|
+
```typescript
|
|
1098
|
+
// 1. Prototype pollution via object spread
|
|
1099
|
+
// REVIEW: Does this accept __proto__ or constructor keys?
|
|
1100
|
+
const config = { ...defaults, ...userInput };
|
|
1101
|
+
|
|
1102
|
+
// 2. Path traversal in file serving
|
|
1103
|
+
// REVIEW: Is the path normalized and confined to allowed directory?
|
|
1104
|
+
const file = path.join(uploadDir, req.params.filename);
|
|
1105
|
+
|
|
1106
|
+
// 3. NoSQL injection in MongoDB
|
|
1107
|
+
// VULNERABLE
|
|
1108
|
+
const user = await User.findOne({ username: req.body.username });
|
|
1109
|
+
// If req.body.username = { "$ne": "" }, returns first user
|
|
1110
|
+
|
|
1111
|
+
// SECURE
|
|
1112
|
+
const username = String(req.body.username); // Coerce to string
|
|
1113
|
+
const user = await User.findOne({ username });
|
|
1114
|
+
|
|
1115
|
+
// 4. SSRF via user-controlled URLs
|
|
1116
|
+
// REVIEW: Any fetch/axios/got call using user input as URL?
|
|
1117
|
+
|
|
1118
|
+
// 5. Template literal injection
|
|
1119
|
+
// REVIEW: Is user input interpolated into template literals
|
|
1120
|
+
// used for SQL, HTML, or shell commands?
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
**Node.js security review checklist additions:**
|
|
1124
|
+
- `--experimental-permissions` flag used in production (Node 20+)
|
|
1125
|
+
- `npm audit` clean or all findings triaged
|
|
1126
|
+
- `helmet` middleware applied for HTTP security headers
|
|
1127
|
+
- `express-rate-limit` on authentication and expensive endpoints
|
|
1128
|
+
- No use of `eval()`, `Function()`, `vm.runInNewContext()` with user input
|
|
1129
|
+
|
|
1130
|
+
### 7.2 Python
|
|
1131
|
+
|
|
1132
|
+
**Common vulnerability patterns:**
|
|
1133
|
+
```python
|
|
1134
|
+
# 1. Pickle deserialization — always flag
|
|
1135
|
+
pickle.loads(user_data) # RCE
|
|
1136
|
+
yaml.load(user_data) # RCE — use yaml.safe_load()
|
|
1137
|
+
marshal.loads(user_data) # RCE
|
|
1138
|
+
|
|
1139
|
+
# 2. Format string injection
|
|
1140
|
+
# VULNERABLE
|
|
1141
|
+
log.info(user_input) # If user_input contains %(...)s
|
|
1142
|
+
# SECURE
|
|
1143
|
+
log.info("%s", user_input)
|
|
1144
|
+
|
|
1145
|
+
# 3. Django ORM bypass
|
|
1146
|
+
# REVIEW: Any use of .raw(), .extra(), or RawSQL?
|
|
1147
|
+
User.objects.raw(f"SELECT * FROM users WHERE name = '{name}'") # BAD
|
|
1148
|
+
User.objects.raw("SELECT * FROM users WHERE name = %s", [name]) # OK
|
|
1149
|
+
|
|
1150
|
+
# 4. Jinja2 SSTI
|
|
1151
|
+
# VULNERABLE
|
|
1152
|
+
template = Template(user_input) # Server-side template injection
|
|
1153
|
+
# SECURE — Never use user input as template source
|
|
1154
|
+
|
|
1155
|
+
# 5. os.path.join with absolute user input
|
|
1156
|
+
os.path.join("/safe/dir", "/etc/passwd") # Returns "/etc/passwd"!
|
|
1157
|
+
# REVIEW: Validate that result starts with expected base path
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
**Python security review checklist additions:**
|
|
1161
|
+
- `bandit` scan clean or findings triaged
|
|
1162
|
+
- `safety check` or `pip-audit` for dependency vulnerabilities
|
|
1163
|
+
- No `pickle`, `marshal`, `shelve` with untrusted data
|
|
1164
|
+
- Django: `DEBUG = False` in production, `ALLOWED_HOSTS` configured
|
|
1165
|
+
- Flask: `SECRET_KEY` from environment, not hardcoded
|
|
1166
|
+
|
|
1167
|
+
### 7.3 Kotlin / Swift (Mobile)
|
|
1168
|
+
|
|
1169
|
+
**Kotlin (Android) review patterns:**
|
|
1170
|
+
```kotlin
|
|
1171
|
+
// 1. Insecure data storage
|
|
1172
|
+
// REVIEW: Is sensitive data stored in SharedPreferences without encryption?
|
|
1173
|
+
// VULNERABLE
|
|
1174
|
+
val prefs = getSharedPreferences("auth", MODE_PRIVATE)
|
|
1175
|
+
prefs.edit().putString("token", authToken).apply()
|
|
1176
|
+
|
|
1177
|
+
// SECURE — Use EncryptedSharedPreferences
|
|
1178
|
+
val masterKey = MasterKey.Builder(context)
|
|
1179
|
+
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
|
|
1180
|
+
val prefs = EncryptedSharedPreferences.create(
|
|
1181
|
+
context, "auth", masterKey,
|
|
1182
|
+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
|
1183
|
+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
|
1184
|
+
)
|
|
1185
|
+
|
|
1186
|
+
// 2. WebView JavaScript bridge
|
|
1187
|
+
// REVIEW: Is addJavascriptInterface used? Check API level and interface scope
|
|
1188
|
+
webView.addJavascriptInterface(BridgeObject(), "bridge")
|
|
1189
|
+
// Vulnerable on API < 17: all public methods exposed
|
|
1190
|
+
|
|
1191
|
+
// 3. Intent handling
|
|
1192
|
+
// REVIEW: Are exported activities/services properly protected?
|
|
1193
|
+
// Check AndroidManifest.xml: exported="true" without permission guards
|
|
1194
|
+
|
|
1195
|
+
// 4. Certificate pinning
|
|
1196
|
+
// REVIEW: Is certificate pinning implemented for sensitive APIs?
|
|
1197
|
+
```
|
|
1198
|
+
|
|
1199
|
+
**Swift (iOS) review patterns:**
|
|
1200
|
+
```swift
|
|
1201
|
+
// 1. Keychain usage
|
|
1202
|
+
// REVIEW: Is sensitive data stored in Keychain, not UserDefaults?
|
|
1203
|
+
// VULNERABLE
|
|
1204
|
+
UserDefaults.standard.set(token, forKey: "authToken")
|
|
1205
|
+
|
|
1206
|
+
// SECURE
|
|
1207
|
+
let query: [String: Any] = [
|
|
1208
|
+
kSecClass as String: kSecClassGenericPassword,
|
|
1209
|
+
kSecAttrAccount as String: "authToken",
|
|
1210
|
+
kSecValueData as String: token.data(using: .utf8)!,
|
|
1211
|
+
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
|
|
1212
|
+
]
|
|
1213
|
+
SecItemAdd(query as CFDictionary, nil)
|
|
1214
|
+
|
|
1215
|
+
// 2. ATS (App Transport Security)
|
|
1216
|
+
// REVIEW: Any NSAllowsArbitraryLoads exceptions in Info.plist?
|
|
1217
|
+
|
|
1218
|
+
// 3. URL scheme handling
|
|
1219
|
+
// REVIEW: Is URL scheme input validated before processing?
|
|
1220
|
+
func application(_ app: UIApplication, open url: URL, options: ...) -> Bool {
|
|
1221
|
+
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
|
|
1222
|
+
components.scheme == "myapp",
|
|
1223
|
+
let action = components.host else { return false }
|
|
1224
|
+
// Validate action against allowlist
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// 4. Biometric authentication
|
|
1228
|
+
// REVIEW: Is LAContext properly configured with fallback handling?
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
### 7.4 Infrastructure as Code (IaC) Review
|
|
1232
|
+
|
|
1233
|
+
```hcl
|
|
1234
|
+
# Terraform — Common security issues to review
|
|
1235
|
+
|
|
1236
|
+
# 1. Public S3 bucket
|
|
1237
|
+
# VULNERABLE
|
|
1238
|
+
resource "aws_s3_bucket" "data" {
|
|
1239
|
+
bucket = "company-data"
|
|
1240
|
+
acl = "public-read" # FLAG: Public access
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
# SECURE
|
|
1244
|
+
resource "aws_s3_bucket_public_access_block" "data" {
|
|
1245
|
+
bucket = aws_s3_bucket.data.id
|
|
1246
|
+
block_public_acls = true
|
|
1247
|
+
block_public_policy = true
|
|
1248
|
+
ignore_public_acls = true
|
|
1249
|
+
restrict_public_buckets = true
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
# 2. Overly permissive IAM
|
|
1253
|
+
# VULNERABLE
|
|
1254
|
+
resource "aws_iam_policy" "admin" {
|
|
1255
|
+
policy = jsonencode({
|
|
1256
|
+
Statement = [{
|
|
1257
|
+
Effect = "Allow"
|
|
1258
|
+
Action = "*" # FLAG: Wildcard actions
|
|
1259
|
+
Resource = "*" # FLAG: Wildcard resources
|
|
1260
|
+
}]
|
|
1261
|
+
})
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
# 3. Unencrypted storage
|
|
1265
|
+
# REVIEW: Is encryption_configuration present for RDS, EBS, S3, DynamoDB?
|
|
1266
|
+
|
|
1267
|
+
# 4. Security group rules
|
|
1268
|
+
# VULNERABLE
|
|
1269
|
+
resource "aws_security_group_rule" "ssh" {
|
|
1270
|
+
type = "ingress"
|
|
1271
|
+
from_port = 22
|
|
1272
|
+
to_port = 22
|
|
1273
|
+
protocol = "tcp"
|
|
1274
|
+
cidr_blocks = ["0.0.0.0/0"] # FLAG: Open to world
|
|
1275
|
+
}
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
**IaC scanning tools:**
|
|
1279
|
+
```bash
|
|
1280
|
+
# Checkov
|
|
1281
|
+
pip install checkov
|
|
1282
|
+
checkov -d . --framework terraform
|
|
1283
|
+
|
|
1284
|
+
# tfsec
|
|
1285
|
+
brew install tfsec
|
|
1286
|
+
tfsec .
|
|
1287
|
+
|
|
1288
|
+
# Trivy (multi-purpose)
|
|
1289
|
+
trivy config .
|
|
1290
|
+
```
|
|
1291
|
+
|
|
1292
|
+
---
|
|
1293
|
+
|
|
1294
|
+
## 8. Incident Patterns
|
|
1295
|
+
|
|
1296
|
+
### 8.1 Post-Incident Code Review Process
|
|
1297
|
+
|
|
1298
|
+
When a security incident traces back to a code-level vulnerability, conduct
|
|
1299
|
+
a structured post-incident code review:
|
|
1300
|
+
|
|
1301
|
+
```
|
|
1302
|
+
┌─────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
1303
|
+
│ Identify │ │ Variant │ │ Process │ │ Prevention │
|
|
1304
|
+
│ Root Cause │───>│ Analysis │───>│ Gap │───>│ Measures │
|
|
1305
|
+
│ │ │ │ │ Analysis │ │ │
|
|
1306
|
+
└─────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
**Step 1: Root Cause Identification**
|
|
1310
|
+
- Identify the exact vulnerable code (commit, file, line)
|
|
1311
|
+
- Determine when the vulnerability was introduced (git blame)
|
|
1312
|
+
- Identify what review process the code went through
|
|
1313
|
+
- Document the attack vector and exploitation method
|
|
1314
|
+
|
|
1315
|
+
**Step 2: Variant Analysis**
|
|
1316
|
+
- Search the entire codebase for the same vulnerability pattern
|
|
1317
|
+
- Use CodeQL or Semgrep to write a query for the specific pattern
|
|
1318
|
+
- Check third-party dependencies for the same class of issue
|
|
1319
|
+
- Review related modules that handle similar data flows
|
|
1320
|
+
|
|
1321
|
+
**Step 3: Process Gap Analysis**
|
|
1322
|
+
- Was there a code review? Did the reviewer have security training?
|
|
1323
|
+
- Were automated tools running? Did they miss this class of bug?
|
|
1324
|
+
- Was the threat model up to date? Did it cover this attack surface?
|
|
1325
|
+
- Were there existing tests that should have caught this?
|
|
1326
|
+
|
|
1327
|
+
**Step 4: Prevention Measures**
|
|
1328
|
+
- Write automated rules (Semgrep/CodeQL) to detect the pattern
|
|
1329
|
+
- Add the pattern to the team's security review checklist
|
|
1330
|
+
- Create regression tests for the specific vulnerability
|
|
1331
|
+
- Update security training materials with this example
|
|
1332
|
+
|
|
1333
|
+
### 8.2 Root Cause Analysis Template
|
|
1334
|
+
|
|
1335
|
+
```markdown
|
|
1336
|
+
## Security Incident RCA — Code Review Findings
|
|
1337
|
+
|
|
1338
|
+
### Incident Summary
|
|
1339
|
+
- **Date discovered:** YYYY-MM-DD
|
|
1340
|
+
- **Severity:** Critical / High / Medium / Low
|
|
1341
|
+
- **CVE (if applicable):** CVE-YYYY-NNNNN
|
|
1342
|
+
- **Affected systems:** [list]
|
|
1343
|
+
|
|
1344
|
+
### Vulnerability Details
|
|
1345
|
+
- **CWE classification:** CWE-XXX
|
|
1346
|
+
- **Vulnerable code location:** file:line
|
|
1347
|
+
- **Introduced in commit:** [hash]
|
|
1348
|
+
- **Introduced date:** YYYY-MM-DD
|
|
1349
|
+
- **Introduced by:** [developer — for process, not blame]
|
|
1350
|
+
|
|
1351
|
+
### Why It Was Missed
|
|
1352
|
+
- [ ] No code review performed
|
|
1353
|
+
- [ ] Code review performed but reviewer lacked security knowledge
|
|
1354
|
+
- [ ] Automated tools not configured for this vulnerability class
|
|
1355
|
+
- [ ] Vulnerability in third-party dependency
|
|
1356
|
+
- [ ] Complex multi-step vulnerability hard to spot in review
|
|
1357
|
+
- [ ] Business logic flaw not detectable by automated tools
|
|
1358
|
+
|
|
1359
|
+
### Remediation
|
|
1360
|
+
- **Immediate fix:** [PR link]
|
|
1361
|
+
- **Variant scan results:** [N similar issues found]
|
|
1362
|
+
- **Automated rule created:** [rule ID / link]
|
|
1363
|
+
- **Regression test added:** [test file link]
|
|
1364
|
+
|
|
1365
|
+
### Process Improvements
|
|
1366
|
+
1. [Specific improvement with owner and deadline]
|
|
1367
|
+
2. [...]
|
|
1368
|
+
```
|
|
1369
|
+
|
|
1370
|
+
### 8.3 Security Regression Prevention
|
|
1371
|
+
|
|
1372
|
+
```yaml
|
|
1373
|
+
# Example: Semgrep rule created after an incident
|
|
1374
|
+
rules:
|
|
1375
|
+
- id: incident-2024-042-sql-concat
|
|
1376
|
+
message: |
|
|
1377
|
+
SQL string concatenation detected. This pattern caused incident
|
|
1378
|
+
INC-2024-042. Use parameterized queries instead.
|
|
1379
|
+
See: https://wiki.internal/incidents/INC-2024-042
|
|
1380
|
+
patterns:
|
|
1381
|
+
- pattern-either:
|
|
1382
|
+
- pattern: $DB.query("..." + $VAR + "...")
|
|
1383
|
+
- pattern: $DB.query(f"...{$VAR}...")
|
|
1384
|
+
severity: ERROR
|
|
1385
|
+
languages: [python]
|
|
1386
|
+
metadata:
|
|
1387
|
+
incident: INC-2024-042
|
|
1388
|
+
cwe: CWE-89
|
|
1389
|
+
```
|
|
1390
|
+
|
|
1391
|
+
**Regression test example:**
|
|
1392
|
+
```python
|
|
1393
|
+
# test_security_regressions.py
|
|
1394
|
+
"""
|
|
1395
|
+
Security regression tests — each test corresponds to a past incident.
|
|
1396
|
+
DO NOT DELETE these tests without security team approval.
|
|
1397
|
+
"""
|
|
1398
|
+
|
|
1399
|
+
def test_inc_2024_042_sql_injection():
|
|
1400
|
+
"""Regression: SQL injection via order search (INC-2024-042)"""
|
|
1401
|
+
malicious_input = "'; DROP TABLE orders; --"
|
|
1402
|
+
response = client.get(f"/api/orders?search={malicious_input}")
|
|
1403
|
+
assert response.status_code == 200
|
|
1404
|
+
# Verify orders table still exists
|
|
1405
|
+
assert Order.objects.count() > 0
|
|
1406
|
+
|
|
1407
|
+
def test_inc_2024_051_idor_order_access():
|
|
1408
|
+
"""Regression: IDOR in order endpoint (INC-2024-051)"""
|
|
1409
|
+
# User A should not access User B's orders
|
|
1410
|
+
client.login(user_a)
|
|
1411
|
+
response = client.get(f"/api/orders/{user_b_order_id}")
|
|
1412
|
+
assert response.status_code == 404 # Not 200
|
|
1413
|
+
```
|
|
1414
|
+
|
|
1415
|
+
---
|
|
1416
|
+
|
|
1417
|
+
## 9. Compliance & Standards
|
|
1418
|
+
|
|
1419
|
+
### 9.1 OWASP Code Review Guide
|
|
1420
|
+
|
|
1421
|
+
The OWASP Code Review Guide (v2.0) provides a structured methodology:
|
|
1422
|
+
|
|
1423
|
+
1. **Understand the application** — Architecture, data flows, trust boundaries
|
|
1424
|
+
2. **Identify high-risk code** — Auth, crypto, input handling, file operations
|
|
1425
|
+
3. **Review against OWASP Top 10** — Each category has specific code patterns
|
|
1426
|
+
4. **Document findings** — Severity, location, remediation guidance
|
|
1427
|
+
5. **Verify fixes** — Re-review remediated code
|
|
1428
|
+
|
|
1429
|
+
**OWASP Top 10 (2025) code review mapping:**
|
|
1430
|
+
|
|
1431
|
+
| Risk Category | Code Review Focus |
|
|
1432
|
+
|----------------------------------------|-------------------------------------------|
|
|
1433
|
+
| A01: Broken Access Control | AuthZ checks on every endpoint, IDOR |
|
|
1434
|
+
| A02: Cryptographic Failures | Algorithm choice, key management |
|
|
1435
|
+
| A03: Injection | Parameterized queries, input validation |
|
|
1436
|
+
| A04: Insecure Design | Threat modeling, security requirements |
|
|
1437
|
+
| A05: Security Misconfiguration | Debug flags, default credentials, headers |
|
|
1438
|
+
| A06: Vulnerable Components | Dependency versions, known CVEs |
|
|
1439
|
+
| A07: Authentication Failures | Credential handling, session management |
|
|
1440
|
+
| A08: Software/Data Integrity Failures | Deserialization, CI/CD pipeline security |
|
|
1441
|
+
| A09: Logging/Monitoring Failures | Security event logging, log injection |
|
|
1442
|
+
| A10: SSRF | URL validation, network segmentation |
|
|
1443
|
+
| NEW: Supply Chain Failures | Dependency provenance, lockfile integrity |
|
|
1444
|
+
| NEW: Mishandling Exceptional Conditions| Error handling, fail-closed patterns |
|
|
1445
|
+
|
|
1446
|
+
### 9.2 NIST Secure Software Development Framework (SSDF)
|
|
1447
|
+
|
|
1448
|
+
NIST SP 800-218 defines four practice groups relevant to code review:
|
|
1449
|
+
|
|
1450
|
+
| Practice Group | Code Review Relevance |
|
|
1451
|
+
|-------------------------|---------------------------------------------------|
|
|
1452
|
+
| PO: Prepare | Define security requirements, training reviewers |
|
|
1453
|
+
| PS: Protect Software | Secure development environment, access controls |
|
|
1454
|
+
| PW: Produce Well-Secured| Code review as verification, SAST integration |
|
|
1455
|
+
| RV: Respond to Vulns | Incident response, patch process, variant analysis|
|
|
1456
|
+
|
|
1457
|
+
**Key SSDF practices for code review (PW category):**
|
|
1458
|
+
- **PW.7.1** — Acquire and maintain well-secured components
|
|
1459
|
+
- **PW.7.2** — Verify components have no known vulnerabilities
|
|
1460
|
+
- **PW.8.1** — Review code for security vulnerabilities using human review
|
|
1461
|
+
- **PW.8.2** — Review code using automated tools (SAST)
|
|
1462
|
+
- **PW.9.1** — Test executable code for vulnerabilities
|
|
1463
|
+
|
|
1464
|
+
### 9.3 CERT Coding Standards
|
|
1465
|
+
|
|
1466
|
+
SEI CERT provides language-specific rules prioritized by severity,
|
|
1467
|
+
likelihood, and remediation cost:
|
|
1468
|
+
|
|
1469
|
+
**CERT C Secure Coding Standard (selected high-priority rules):**
|
|
1470
|
+
- **STR31-C** — Guarantee storage for strings has sufficient space
|
|
1471
|
+
- **INT32-C** — Ensure integer operations do not overflow
|
|
1472
|
+
- **FIO30-C** — Exclude user input from format strings
|
|
1473
|
+
- **MSC33-C** — Do not pass invalid data to the asctime() function
|
|
1474
|
+
- **MEM35-C** — Allocate sufficient memory for an object
|
|
1475
|
+
|
|
1476
|
+
**CERT Java Secure Coding Standard (selected rules):**
|
|
1477
|
+
- **IDS00-J** — Prevent SQL injection
|
|
1478
|
+
- **IDS01-J** — Normalize strings before validating them
|
|
1479
|
+
- **SER01-J** — Do not deviate from the proper signatures of serialization methods
|
|
1480
|
+
- **MSC02-J** — Generate strong random numbers
|
|
1481
|
+
- **ENV02-J** — Do not trust the values of environment variables
|
|
1482
|
+
|
|
1483
|
+
**CERT rules integrate with tools:**
|
|
1484
|
+
- Semgrep has CERT-mapped rules in the community registry
|
|
1485
|
+
- SonarQube maps findings to CERT identifiers
|
|
1486
|
+
- CodeQL provides CERT-aligned query suites
|
|
1487
|
+
|
|
1488
|
+
### 9.4 Compliance Framework Mapping
|
|
1489
|
+
|
|
1490
|
+
| Framework | Code Review Requirement | Control ID |
|
|
1491
|
+
|-------------|---------------------------------------------------|-----------------|
|
|
1492
|
+
| PCI DSS 4.0 | Secure coding training, code review for vulns | 6.2.3, 6.2.4 |
|
|
1493
|
+
| SOC 2 | Change management, peer review of code changes | CC8.1 |
|
|
1494
|
+
| HIPAA | Access controls, audit logging in application | 164.312(a)(1) |
|
|
1495
|
+
| ISO 27001 | Secure development policy, code review process | A.8.25-A.8.28 |
|
|
1496
|
+
| FedRAMP | SAST scanning, vulnerability remediation | SA-11, SI-10 |
|
|
1497
|
+
|
|
1498
|
+
---
|
|
1499
|
+
|
|
1500
|
+
## 10. Code Examples: Vulnerable to Secure Patterns
|
|
1501
|
+
|
|
1502
|
+
### Example 1: JWT Validation (TypeScript)
|
|
1503
|
+
|
|
1504
|
+
```typescript
|
|
1505
|
+
// VULNERABLE — No signature verification
|
|
1506
|
+
import jwt from 'jsonwebtoken';
|
|
1507
|
+
function getUser(token: string) {
|
|
1508
|
+
const payload = jwt.decode(token); // Decodes WITHOUT verifying
|
|
1509
|
+
return payload;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
// SECURE — Full validation
|
|
1513
|
+
function getUser(token: string) {
|
|
1514
|
+
try {
|
|
1515
|
+
const payload = jwt.verify(token, process.env.JWT_SECRET!, {
|
|
1516
|
+
algorithms: ['HS256'], // Restrict algorithms
|
|
1517
|
+
issuer: 'auth.example.com',
|
|
1518
|
+
audience: 'api.example.com',
|
|
1519
|
+
maxAge: '1h',
|
|
1520
|
+
clockTolerance: 30,
|
|
1521
|
+
});
|
|
1522
|
+
return payload;
|
|
1523
|
+
} catch (err) {
|
|
1524
|
+
throw new AuthenticationError('Invalid token');
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
```
|
|
1528
|
+
|
|
1529
|
+
### Example 2: Password Reset (Python)
|
|
1530
|
+
|
|
1531
|
+
```python
|
|
1532
|
+
# VULNERABLE — Predictable token, no expiry
|
|
1533
|
+
import hashlib
|
|
1534
|
+
def create_reset_token(user_id):
|
|
1535
|
+
token = hashlib.md5(str(user_id).encode()).hexdigest()
|
|
1536
|
+
db.save_reset_token(user_id, token) # No expiry set
|
|
1537
|
+
return token
|
|
1538
|
+
|
|
1539
|
+
# SECURE — Cryptographic token, expiry, single-use
|
|
1540
|
+
import secrets
|
|
1541
|
+
from datetime import datetime, timedelta
|
|
1542
|
+
|
|
1543
|
+
def create_reset_token(user_id):
|
|
1544
|
+
token = secrets.token_urlsafe(32)
|
|
1545
|
+
token_hash = hashlib.sha256(token.encode()).hexdigest()
|
|
1546
|
+
db.save_reset_token(
|
|
1547
|
+
user_id=user_id,
|
|
1548
|
+
token_hash=token_hash, # Store hash, not plaintext
|
|
1549
|
+
expires_at=datetime.utcnow() + timedelta(hours=1),
|
|
1550
|
+
used=False
|
|
1551
|
+
)
|
|
1552
|
+
return token # Send plaintext to user via email
|
|
1553
|
+
|
|
1554
|
+
def verify_reset_token(token):
|
|
1555
|
+
token_hash = hashlib.sha256(token.encode()).hexdigest()
|
|
1556
|
+
record = db.get_reset_token(token_hash)
|
|
1557
|
+
if not record or record.used or record.expires_at < datetime.utcnow():
|
|
1558
|
+
raise InvalidTokenError()
|
|
1559
|
+
db.mark_token_used(token_hash) # Single-use
|
|
1560
|
+
return record.user_id
|
|
1561
|
+
```
|
|
1562
|
+
|
|
1563
|
+
### Example 3: File Download (Go)
|
|
1564
|
+
|
|
1565
|
+
```go
|
|
1566
|
+
// VULNERABLE — Path traversal
|
|
1567
|
+
func downloadHandler(w http.ResponseWriter, r *http.Request) {
|
|
1568
|
+
filename := r.URL.Query().Get("file")
|
|
1569
|
+
http.ServeFile(w, r, filepath.Join("./uploads", filename))
|
|
1570
|
+
// file=../../../etc/passwd
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
// SECURE — Sanitized path with confinement check
|
|
1574
|
+
func downloadHandler(w http.ResponseWriter, r *http.Request) {
|
|
1575
|
+
filename := filepath.Base(r.URL.Query().Get("file")) // Strip directory
|
|
1576
|
+
if filename == "." || filename == "/" {
|
|
1577
|
+
http.Error(w, "Invalid filename", http.StatusBadRequest)
|
|
1578
|
+
return
|
|
1579
|
+
}
|
|
1580
|
+
fullPath := filepath.Join("./uploads", filename)
|
|
1581
|
+
absPath, err := filepath.Abs(fullPath)
|
|
1582
|
+
if err != nil || !strings.HasPrefix(absPath, "/app/uploads") {
|
|
1583
|
+
http.Error(w, "Forbidden", http.StatusForbidden)
|
|
1584
|
+
return
|
|
1585
|
+
}
|
|
1586
|
+
http.ServeFile(w, r, absPath)
|
|
1587
|
+
}
|
|
1588
|
+
```
|
|
1589
|
+
|
|
1590
|
+
### Example 4: API Rate Limiting (TypeScript)
|
|
1591
|
+
|
|
1592
|
+
```typescript
|
|
1593
|
+
// VULNERABLE — No rate limiting on sensitive endpoint
|
|
1594
|
+
app.post('/api/login', async (req, res) => {
|
|
1595
|
+
const { email, password } = req.body;
|
|
1596
|
+
// Unlimited brute force attempts possible
|
|
1597
|
+
const user = await authenticate(email, password);
|
|
1598
|
+
res.json({ token: generateToken(user) });
|
|
1599
|
+
});
|
|
1600
|
+
|
|
1601
|
+
// SECURE — Rate limiting with progressive delays
|
|
1602
|
+
import rateLimit from 'express-rate-limit';
|
|
1603
|
+
import RedisStore from 'rate-limit-redis';
|
|
1604
|
+
|
|
1605
|
+
const loginLimiter = rateLimit({
|
|
1606
|
+
store: new RedisStore({ sendCommand: (...args) => redisClient.sendCommand(args) }),
|
|
1607
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
1608
|
+
max: 5, // 5 attempts per window
|
|
1609
|
+
skipSuccessfulRequests: true,
|
|
1610
|
+
standardHeaders: true,
|
|
1611
|
+
legacyHeaders: false,
|
|
1612
|
+
keyGenerator: (req) => req.body.email || req.ip, // Per-account limiting
|
|
1613
|
+
handler: (req, res) => {
|
|
1614
|
+
res.status(429).json({
|
|
1615
|
+
error: 'Too many login attempts. Please try again later.',
|
|
1616
|
+
retryAfter: res.getHeader('Retry-After'),
|
|
1617
|
+
});
|
|
1618
|
+
},
|
|
1619
|
+
});
|
|
1620
|
+
|
|
1621
|
+
app.post('/api/login', loginLimiter, async (req, res) => {
|
|
1622
|
+
// ... authentication logic
|
|
1623
|
+
});
|
|
1624
|
+
```
|
|
1625
|
+
|
|
1626
|
+
### Example 5: Secure Cookie Configuration (TypeScript)
|
|
1627
|
+
|
|
1628
|
+
```typescript
|
|
1629
|
+
// VULNERABLE — Insecure session cookie
|
|
1630
|
+
app.use(session({
|
|
1631
|
+
secret: 'keyboard cat', // Weak, hardcoded secret
|
|
1632
|
+
cookie: {} // Default: httpOnly false, secure false
|
|
1633
|
+
}));
|
|
1634
|
+
|
|
1635
|
+
// SECURE — Hardened session configuration
|
|
1636
|
+
app.use(session({
|
|
1637
|
+
secret: process.env.SESSION_SECRET, // Strong, from environment
|
|
1638
|
+
name: '__Host-sid', // Cookie prefix for extra protection
|
|
1639
|
+
resave: false,
|
|
1640
|
+
saveUninitialized: false,
|
|
1641
|
+
cookie: {
|
|
1642
|
+
httpOnly: true, // No JavaScript access
|
|
1643
|
+
secure: true, // HTTPS only
|
|
1644
|
+
sameSite: 'strict', // CSRF protection
|
|
1645
|
+
maxAge: 3600000, // 1 hour
|
|
1646
|
+
domain: undefined, // No cross-subdomain
|
|
1647
|
+
path: '/',
|
|
1648
|
+
},
|
|
1649
|
+
store: new RedisStore({ client: redisClient }), // Server-side storage
|
|
1650
|
+
}));
|
|
1651
|
+
```
|
|
1652
|
+
|
|
1653
|
+
### Example 6: Semgrep Custom Rule — Detect Dangerous Deserialization
|
|
1654
|
+
|
|
1655
|
+
```yaml
|
|
1656
|
+
rules:
|
|
1657
|
+
- id: dangerous-deserialization
|
|
1658
|
+
message: |
|
|
1659
|
+
Deserialization of untrusted data detected. This can lead to
|
|
1660
|
+
remote code execution. Use JSON or a safe serialization format.
|
|
1661
|
+
patterns:
|
|
1662
|
+
- pattern-either:
|
|
1663
|
+
# Python
|
|
1664
|
+
- pattern: pickle.loads(...)
|
|
1665
|
+
- pattern: pickle.load(...)
|
|
1666
|
+
- pattern: yaml.load(...)
|
|
1667
|
+
- pattern: marshal.loads(...)
|
|
1668
|
+
- pattern: shelve.open(...)
|
|
1669
|
+
# Java
|
|
1670
|
+
- pattern: (ObjectInputStream $X).readObject()
|
|
1671
|
+
- pattern: (XMLDecoder $X).readObject()
|
|
1672
|
+
# Ruby
|
|
1673
|
+
- pattern: Marshal.load(...)
|
|
1674
|
+
- pattern: YAML.load(...)
|
|
1675
|
+
# PHP
|
|
1676
|
+
- pattern: unserialize(...)
|
|
1677
|
+
severity: ERROR
|
|
1678
|
+
languages: [python, java, ruby, php]
|
|
1679
|
+
metadata:
|
|
1680
|
+
cwe: CWE-502
|
|
1681
|
+
owasp: A08:2021 Software and Data Integrity Failures
|
|
1682
|
+
references:
|
|
1683
|
+
- https://owasp.org/www-community/vulnerabilities/Insecure_Deserialization
|
|
1684
|
+
```
|
|
1685
|
+
|
|
1686
|
+
### Example 7: Semgrep Custom Rule — Missing CSRF Protection
|
|
1687
|
+
|
|
1688
|
+
```yaml
|
|
1689
|
+
rules:
|
|
1690
|
+
- id: express-missing-csrf
|
|
1691
|
+
message: |
|
|
1692
|
+
State-changing route handler without CSRF protection.
|
|
1693
|
+
Add CSRF middleware (csurf or csrf-csrf) to POST/PUT/DELETE routes.
|
|
1694
|
+
patterns:
|
|
1695
|
+
- pattern-either:
|
|
1696
|
+
- pattern: app.post($PATH, ..., $HANDLER)
|
|
1697
|
+
- pattern: app.put($PATH, ..., $HANDLER)
|
|
1698
|
+
- pattern: app.delete($PATH, ..., $HANDLER)
|
|
1699
|
+
- pattern: router.post($PATH, ..., $HANDLER)
|
|
1700
|
+
- pattern: router.put($PATH, ..., $HANDLER)
|
|
1701
|
+
- pattern: router.delete($PATH, ..., $HANDLER)
|
|
1702
|
+
- pattern-not: app.$METHOD($PATH, ..., csrfProtection, ..., $HANDLER)
|
|
1703
|
+
- pattern-not: router.$METHOD($PATH, ..., csrfProtection, ..., $HANDLER)
|
|
1704
|
+
severity: WARNING
|
|
1705
|
+
languages: [javascript, typescript]
|
|
1706
|
+
metadata:
|
|
1707
|
+
cwe: CWE-352
|
|
1708
|
+
owasp: A01:2021 Broken Access Control
|
|
1709
|
+
```
|
|
1710
|
+
|
|
1711
|
+
### Example 8: Secure Logging Configuration (Python)
|
|
1712
|
+
|
|
1713
|
+
```python
|
|
1714
|
+
# VULNERABLE — Sensitive data in logs
|
|
1715
|
+
import logging
|
|
1716
|
+
logger = logging.getLogger(__name__)
|
|
1717
|
+
|
|
1718
|
+
def process_payment(card_number, amount):
|
|
1719
|
+
logger.info(f"Processing payment: card={card_number}, amount={amount}")
|
|
1720
|
+
# Logs: "Processing payment: card=4111111111111111, amount=99.99"
|
|
1721
|
+
|
|
1722
|
+
# SECURE — Sensitive data masked
|
|
1723
|
+
import re
|
|
1724
|
+
|
|
1725
|
+
class SensitiveDataFilter(logging.Filter):
|
|
1726
|
+
PATTERNS = [
|
|
1727
|
+
(re.compile(r'\b\d{13,16}\b'), '[CARD_REDACTED]'),
|
|
1728
|
+
(re.compile(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'),
|
|
1729
|
+
'[EMAIL_REDACTED]'),
|
|
1730
|
+
(re.compile(r'(?i)(password|secret|token|key)\s*[=:]\s*\S+'),
|
|
1731
|
+
r'\1=[REDACTED]'),
|
|
1732
|
+
]
|
|
1733
|
+
|
|
1734
|
+
def filter(self, record):
|
|
1735
|
+
msg = record.getMessage()
|
|
1736
|
+
for pattern, replacement in self.PATTERNS:
|
|
1737
|
+
msg = pattern.sub(replacement, msg)
|
|
1738
|
+
record.msg = msg
|
|
1739
|
+
record.args = ()
|
|
1740
|
+
return True
|
|
1741
|
+
|
|
1742
|
+
logger.addFilter(SensitiveDataFilter())
|
|
1743
|
+
|
|
1744
|
+
def process_payment(card_number, amount):
|
|
1745
|
+
masked_card = f"****{card_number[-4:]}"
|
|
1746
|
+
logger.info(f"Processing payment: card={masked_card}, amount={amount}")
|
|
1747
|
+
```
|
|
1748
|
+
|
|
1749
|
+
---
|
|
1750
|
+
|
|
1751
|
+
## References
|
|
1752
|
+
|
|
1753
|
+
- [OWASP Code Review Guide](https://owasp.org/www-project-code-review-guide/)
|
|
1754
|
+
- [OWASP Secure Code Review Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secure_Code_Review_Cheat_Sheet.html)
|
|
1755
|
+
- [NIST SP 800-218 — Secure Software Development Framework](https://csrc.nist.gov/projects/ssdf)
|
|
1756
|
+
- [SEI CERT Coding Standards](https://wiki.sei.cmu.edu/confluence/display/seccode)
|
|
1757
|
+
- [Semgrep Rule Registry](https://semgrep.dev/explore)
|
|
1758
|
+
- [CodeQL Documentation](https://codeql.github.com/docs/)
|
|
1759
|
+
- [CWE/SANS Top 25 Most Dangerous Software Weaknesses](https://cwe.mitre.org/top25/)
|
|
1760
|
+
- [HackerOne — Cost Savings of Fixing Security Flaws in Development](https://www.hackerone.com/blog/cost-savings-fixing-security-flaws)
|
|
1761
|
+
- [GitGuardian State of Secrets Sprawl 2025](https://www.gitguardian.com/state-of-secrets-sprawl-report)
|
|
1762
|
+
- [GitHub Advanced Security](https://github.com/security/advanced-security)
|
|
1763
|
+
- [OWASP Top 10 2025](https://owasp.org/www-project-top-ten/)
|
|
1764
|
+
- [Bandit — Python Security Linter](https://bandit.readthedocs.io/)
|
|
1765
|
+
- [eslint-plugin-security](https://github.com/eslint-community/eslint-plugin-security)
|