@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,1618 @@
|
|
|
1
|
+
# Security Logging and Monitoring
|
|
2
|
+
|
|
3
|
+
> **Expertise Module** — Security Infrastructure
|
|
4
|
+
> **Purpose:** Comprehensive guidance for AI agents implementing security logging, monitoring, alerting, and audit trail systems.
|
|
5
|
+
> **Last Updated:** 2026-03-08
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Threat Landscape
|
|
10
|
+
|
|
11
|
+
### The Detection Gap
|
|
12
|
+
|
|
13
|
+
Security logging and monitoring failures represent one of the most critical yet underappreciated
|
|
14
|
+
vulnerabilities in modern systems. Without adequate logging and monitoring, breaches go undetected
|
|
15
|
+
for extended periods, dramatically increasing damage and cost.
|
|
16
|
+
|
|
17
|
+
**Key statistics (IBM Cost of a Data Breach Report 2024):**
|
|
18
|
+
- Average time to identify a breach: **194 days**
|
|
19
|
+
- Average time to contain a breach: **64 days**
|
|
20
|
+
- Combined breach lifecycle: **258 days** (7-year low, down from 277 days)
|
|
21
|
+
- Breaches involving stolen credentials: **292 days** average lifecycle
|
|
22
|
+
- Breaches exceeding 200 days cost **$4.87M** vs **$3.61M** for those contained within 200 days
|
|
23
|
+
|
|
24
|
+
### OWASP A09:2021 — Security Logging and Monitoring Failures
|
|
25
|
+
|
|
26
|
+
Insufficient logging, detection, monitoring, and active response allows attackers to further attack
|
|
27
|
+
systems, maintain persistence, pivot to more systems, and tamper with, extract, or destroy data.
|
|
28
|
+
This category moved up from A10:2017 to A09:2021, reflecting its growing criticality. It remains
|
|
29
|
+
at A09 in OWASP Top 10:2025.
|
|
30
|
+
|
|
31
|
+
**What constitutes failure:**
|
|
32
|
+
- Auditable events (logins, failed logins, high-value transactions) not logged
|
|
33
|
+
- Warnings and errors generate no, inadequate, or unclear log messages
|
|
34
|
+
- Logs not monitored for suspicious activity
|
|
35
|
+
- Logs stored only locally (no centralization)
|
|
36
|
+
- Alerting thresholds and response escalation processes absent or ineffective
|
|
37
|
+
- Penetration testing and scans do not trigger alerts
|
|
38
|
+
- Application unable to detect, escalate, or alert for active attacks in real time
|
|
39
|
+
|
|
40
|
+
### Real-World Breach Case Studies
|
|
41
|
+
|
|
42
|
+
**Equifax (2017) — 76 Days Undetected:**
|
|
43
|
+
- Attackers exploited Apache Struts vulnerability (CVE-2017-5638) starting mid-May 2017
|
|
44
|
+
- Breach went undetected for **76 days** until July 29, 2017
|
|
45
|
+
- Root cause: An **expired SSL certificate** (expired November 2016) disabled network traffic
|
|
46
|
+
inspection tools — the very tools meant to detect data exfiltration
|
|
47
|
+
- Once the certificate was renewed, the monitoring tool immediately flagged suspicious traffic
|
|
48
|
+
- **147.9 million** Americans, 15.2 million British, and 19,000 Canadian citizens compromised
|
|
49
|
+
- Lesson: Monitoring infrastructure must itself be monitored — certificate expiry, agent health,
|
|
50
|
+
pipeline throughput. A single expired certificate created a 10-month blind spot.
|
|
51
|
+
|
|
52
|
+
**SolarWinds / SUNBURST (2020) — Months Undetected:**
|
|
53
|
+
- Attackers (APT29/Cozy Bear) compromised the Orion build pipeline as early as January 2019
|
|
54
|
+
- Malicious code shipped in legitimate software updates starting March 2020
|
|
55
|
+
- Went undetected until December 2020 — discovered by FireEye, not SolarWinds
|
|
56
|
+
- Detection trigger: An anomalous remote login from an unknown device with suspicious IP
|
|
57
|
+
- The malware checked for security tools and disabled them, evading EDR
|
|
58
|
+
- Organizations with **SIEM and centralized logging** were better prepared to investigate
|
|
59
|
+
- Lesson: Behavioral analytics and anomaly detection catch what signature-based tools miss.
|
|
60
|
+
Log retention policies must be long enough to support retrospective investigation.
|
|
61
|
+
|
|
62
|
+
**Log4Shell / CVE-2021-44228 (2021) — Logging as Attack Surface:**
|
|
63
|
+
- Zero-day in Apache Log4j (versions 2.0–2.14.1), CVSS score **10.0**
|
|
64
|
+
- Affected **35,000+ Java packages** (8% of Maven Central)
|
|
65
|
+
- Logging frameworks themselves became the attack vector — JNDI lookup injection
|
|
66
|
+
- Most organizations did not know they used Log4j (buried in transitive dependencies)
|
|
67
|
+
- Lesson: Logging libraries are part of the attack surface. Maintain a Software Bill of
|
|
68
|
+
Materials (SBOM). Never process untrusted input in log format strings.
|
|
69
|
+
|
|
70
|
+
### Attacker Techniques Against Logging (MITRE ATT&CK)
|
|
71
|
+
|
|
72
|
+
| Technique | ATT&CK ID | Description |
|
|
73
|
+
|-----------|-----------|-------------|
|
|
74
|
+
| Indicator Removal: Clear Logs | T1070.001 | Attacker clears Windows Event, Linux syslog, or application logs |
|
|
75
|
+
| Indicator Removal: Timestomp | T1070.006 | Modifying file timestamps to confuse forensic timeline |
|
|
76
|
+
| Impair Defenses: Disable Logging | T1562.002 | Disabling audit logging, syslog, or cloud trail logging |
|
|
77
|
+
| Log Enumeration | T1654 | Attacker reads logs to understand defenses and detection gaps |
|
|
78
|
+
| Impair Defenses: Indicator Blocking | T1562.006 | Preventing security events from being written to logs |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 2. Core Security Principles
|
|
83
|
+
|
|
84
|
+
### 2.1 Log Everything Security-Relevant
|
|
85
|
+
|
|
86
|
+
Every security-meaningful event must generate a log entry. The cost of over-logging is storage;
|
|
87
|
+
the cost of under-logging is an undetected breach.
|
|
88
|
+
|
|
89
|
+
**Mandatory event categories:**
|
|
90
|
+
- Authentication events (success, failure, lockout, MFA challenge)
|
|
91
|
+
- Authorization failures (access denied, privilege escalation attempts)
|
|
92
|
+
- Input validation failures (SQLi attempts, XSS payloads, malformed requests)
|
|
93
|
+
- Administrative actions (user creation, role changes, config modifications)
|
|
94
|
+
- Data access events (read/write to sensitive resources)
|
|
95
|
+
- System events (startup, shutdown, errors, configuration changes)
|
|
96
|
+
- API activity (rate limit hits, unusual patterns, deprecated endpoint usage)
|
|
97
|
+
|
|
98
|
+
### 2.2 Protect Log Integrity
|
|
99
|
+
|
|
100
|
+
Logs are forensic evidence. If attackers can modify logs, they can erase their tracks.
|
|
101
|
+
|
|
102
|
+
- Write logs to append-only storage (WORM — Write Once Read Many)
|
|
103
|
+
- Use centralized logging — logs leave the compromised system immediately
|
|
104
|
+
- Implement cryptographic verification (hash chains, digital signatures)
|
|
105
|
+
- Restrict log access — separate log admin role from system admin role
|
|
106
|
+
- Monitor for log deletion or modification events (meta-monitoring)
|
|
107
|
+
- Synchronize time across all systems using NTP (critical for correlation)
|
|
108
|
+
|
|
109
|
+
### 2.3 Centralize Logs
|
|
110
|
+
|
|
111
|
+
Local-only logs are lost when systems are compromised, destroyed, or rotated.
|
|
112
|
+
|
|
113
|
+
- Ship logs to a centralized, hardened log aggregation system in real time
|
|
114
|
+
- Use secure transport (TLS) for log transmission
|
|
115
|
+
- Implement buffering and retry logic to prevent log loss during outages
|
|
116
|
+
- Maintain geographic redundancy for log storage
|
|
117
|
+
- Ensure log pipeline can handle burst traffic (10x normal volume during incidents)
|
|
118
|
+
|
|
119
|
+
### 2.4 Alert on Anomalies
|
|
120
|
+
|
|
121
|
+
Logs without alerting are write-only storage — forensically useful only after the fact.
|
|
122
|
+
|
|
123
|
+
- Define alerting rules for known attack patterns (brute force, privilege escalation)
|
|
124
|
+
- Implement anomaly detection for behavioral deviations (unusual time, location, volume)
|
|
125
|
+
- Escalate alerts through defined channels (PagerDuty, Slack, email, phone)
|
|
126
|
+
- Tune alerts to minimize false positives while maintaining detection coverage
|
|
127
|
+
- Test alerting regularly — an alert that has never fired might not work
|
|
128
|
+
|
|
129
|
+
### 2.5 Retain for Compliance
|
|
130
|
+
|
|
131
|
+
Different regulations mandate different retention periods:
|
|
132
|
+
|
|
133
|
+
| Standard | Minimum Retention | Notes |
|
|
134
|
+
|----------|-------------------|-------|
|
|
135
|
+
| PCI-DSS Req. 10 | 12 months (3 months immediately accessible) | Cardholder data environment |
|
|
136
|
+
| SOC 2 | 12 months typical | Depends on trust service criteria |
|
|
137
|
+
| HIPAA | 6 years | Audit logs for PHI access |
|
|
138
|
+
| GDPR | As long as necessary, but minimize | Balance with data minimization |
|
|
139
|
+
| NIST 800-92 | Risk-based, organization-defined | Federal agency guidance |
|
|
140
|
+
|
|
141
|
+
### 2.6 Never Log Sensitive Data
|
|
142
|
+
|
|
143
|
+
Logs themselves become a data breach vector if they contain sensitive information.
|
|
144
|
+
|
|
145
|
+
**NEVER log:**
|
|
146
|
+
- Passwords, password hashes, or password reset tokens
|
|
147
|
+
- Session tokens, API keys, or authentication credentials
|
|
148
|
+
- Credit card numbers (PCI-DSS violation)
|
|
149
|
+
- Social Security Numbers or government IDs
|
|
150
|
+
- Full PII (use masking: `user email: j***@e***.com`)
|
|
151
|
+
- Encryption keys or secrets
|
|
152
|
+
- Health information (HIPAA)
|
|
153
|
+
- Raw request bodies that may contain any of the above
|
|
154
|
+
|
|
155
|
+
**ALWAYS log:**
|
|
156
|
+
- User ID (not username in sensitive contexts)
|
|
157
|
+
- Action performed
|
|
158
|
+
- Resource accessed
|
|
159
|
+
- Timestamp (ISO 8601, UTC)
|
|
160
|
+
- Source IP address
|
|
161
|
+
- Request ID / Correlation ID
|
|
162
|
+
- Outcome (success/failure)
|
|
163
|
+
- Reason for failure
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 3. Implementation Patterns
|
|
168
|
+
|
|
169
|
+
### 3.1 Structured Logging (JSON)
|
|
170
|
+
|
|
171
|
+
Unstructured text logs are difficult to parse, query, and correlate. Structured JSON logging is
|
|
172
|
+
the modern standard.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// VULNERABLE: Unstructured logging
|
|
176
|
+
console.log(`User ${username} logged in from ${ip} at ${new Date()}`);
|
|
177
|
+
// Problems: unparseable, injectable, no correlation, inconsistent format
|
|
178
|
+
|
|
179
|
+
// SECURE: Structured JSON logging
|
|
180
|
+
logger.info({
|
|
181
|
+
event: 'authentication.success',
|
|
182
|
+
userId: user.id, // Never log username in auth events
|
|
183
|
+
sourceIp: request.ip,
|
|
184
|
+
userAgent: request.headers['user-agent'],
|
|
185
|
+
correlationId: request.id,
|
|
186
|
+
timestamp: new Date().toISOString(),
|
|
187
|
+
metadata: {
|
|
188
|
+
mfaUsed: true,
|
|
189
|
+
loginMethod: 'password',
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Structured logging advantages:**
|
|
195
|
+
- Machine-parseable — enables automated analysis and SIEM ingestion
|
|
196
|
+
- Consistent schema — every event has the same queryable fields
|
|
197
|
+
- Injection-resistant — JSON serialization escapes control characters
|
|
198
|
+
- Correlation-ready — correlation IDs link related events across services
|
|
199
|
+
- Filterable — query by event type, severity, user, time range
|
|
200
|
+
|
|
201
|
+
### 3.2 Security Event Types to Log
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
enum SecurityEventType {
|
|
205
|
+
// Authentication
|
|
206
|
+
AUTH_LOGIN_SUCCESS = 'auth.login.success',
|
|
207
|
+
AUTH_LOGIN_FAILURE = 'auth.login.failure',
|
|
208
|
+
AUTH_LOGOUT = 'auth.logout',
|
|
209
|
+
AUTH_MFA_CHALLENGE = 'auth.mfa.challenge',
|
|
210
|
+
AUTH_MFA_FAILURE = 'auth.mfa.failure',
|
|
211
|
+
AUTH_PASSWORD_CHANGE = 'auth.password.change',
|
|
212
|
+
AUTH_PASSWORD_RESET = 'auth.password.reset',
|
|
213
|
+
AUTH_ACCOUNT_LOCKED = 'auth.account.locked',
|
|
214
|
+
AUTH_TOKEN_REFRESH = 'auth.token.refresh',
|
|
215
|
+
|
|
216
|
+
// Authorization
|
|
217
|
+
AUTHZ_ACCESS_DENIED = 'authz.access.denied',
|
|
218
|
+
AUTHZ_PRIVILEGE_ESCALATION = 'authz.privilege.escalation',
|
|
219
|
+
AUTHZ_ROLE_CHANGE = 'authz.role.change',
|
|
220
|
+
|
|
221
|
+
// Data Access
|
|
222
|
+
DATA_READ_SENSITIVE = 'data.read.sensitive',
|
|
223
|
+
DATA_EXPORT = 'data.export',
|
|
224
|
+
DATA_DELETE = 'data.delete',
|
|
225
|
+
DATA_BULK_ACCESS = 'data.bulk.access',
|
|
226
|
+
|
|
227
|
+
// Input Validation
|
|
228
|
+
INPUT_VALIDATION_FAILURE = 'input.validation.failure',
|
|
229
|
+
INPUT_SQLI_ATTEMPT = 'input.sqli.attempt',
|
|
230
|
+
INPUT_XSS_ATTEMPT = 'input.xss.attempt',
|
|
231
|
+
|
|
232
|
+
// System
|
|
233
|
+
SYSTEM_CONFIG_CHANGE = 'system.config.change',
|
|
234
|
+
SYSTEM_ADMIN_ACTION = 'system.admin.action',
|
|
235
|
+
SYSTEM_ERROR = 'system.error',
|
|
236
|
+
SYSTEM_STARTUP = 'system.startup',
|
|
237
|
+
SYSTEM_SHUTDOWN = 'system.shutdown',
|
|
238
|
+
|
|
239
|
+
// API
|
|
240
|
+
API_RATE_LIMIT_HIT = 'api.rate_limit.hit',
|
|
241
|
+
API_KEY_CREATED = 'api.key.created',
|
|
242
|
+
API_KEY_REVOKED = 'api.key.revoked',
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### 3.3 Centralized Logging Architecture
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
250
|
+
│ App Server │ │ App Server │ │ App Server │
|
|
251
|
+
│ (Pino/ │ │ (Winston/ │ │ (Python │
|
|
252
|
+
│ Winston) │ │ Bunyan) │ │ logging) │
|
|
253
|
+
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
|
|
254
|
+
│ │ │
|
|
255
|
+
│ Secure Transport (TLS) │
|
|
256
|
+
▼ ▼ ▼
|
|
257
|
+
┌──────────────────────────────────────────────┐
|
|
258
|
+
│ Log Aggregator / Shipper │
|
|
259
|
+
│ (Fluentd / Fluent Bit / Filebeat / │
|
|
260
|
+
│ CloudWatch Agent / Vector) │
|
|
261
|
+
└──────────────────┬───────────────────────────┘
|
|
262
|
+
│
|
|
263
|
+
▼
|
|
264
|
+
┌──────────────────────────────────────────────┐
|
|
265
|
+
│ Central Log Store / SIEM │
|
|
266
|
+
│ (Elasticsearch / Splunk / Sentinel / │
|
|
267
|
+
│ CloudWatch Logs / GCP Cloud Logging) │
|
|
268
|
+
├──────────────────────────────────────────────┤
|
|
269
|
+
│ Alerting Engine │ Dashboards │
|
|
270
|
+
│ (ElastAlert / │ (Kibana / Grafana / │
|
|
271
|
+
│ Splunk Alerts / │ Sentinel Workbooks) │
|
|
272
|
+
│ CloudWatch │ │
|
|
273
|
+
│ Alarms) │ │
|
|
274
|
+
├─────────────────────┴────────────────────────┤
|
|
275
|
+
│ Long-Term Archive (S3 / GCS / Azure Blob) │
|
|
276
|
+
│ WORM / Immutable Storage │
|
|
277
|
+
└──────────────────────────────────────────────┘
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 3.4 SIEM Integration
|
|
281
|
+
|
|
282
|
+
**Key SIEM platforms and their strengths:**
|
|
283
|
+
|
|
284
|
+
| Platform | Strengths | Best For |
|
|
285
|
+
|----------|-----------|----------|
|
|
286
|
+
| Splunk | Mature, powerful SPL query language, extensive app ecosystem | Large enterprises |
|
|
287
|
+
| Microsoft Sentinel | Native Azure/M365 integration, KQL, built-in SOAR | Azure-centric orgs |
|
|
288
|
+
| Elastic SIEM | Open-source core, prebuilt detection rules, ECS schema | Cost-conscious teams |
|
|
289
|
+
| Google Chronicle | Petabyte-scale, YARA-L rules, VirusTotal integration | Google Cloud orgs |
|
|
290
|
+
| Datadog Security | APM + security unified, cloud-native | DevSecOps teams |
|
|
291
|
+
|
|
292
|
+
**Detection rule categories:**
|
|
293
|
+
- **Threshold rules:** Alert when event count exceeds N in time window T
|
|
294
|
+
- **Correlation rules:** Alert when multiple related events occur in sequence
|
|
295
|
+
- **Anomaly rules:** Alert on statistical deviation from baseline behavior
|
|
296
|
+
- **Indicator rules:** Alert on known IOCs (IPs, domains, file hashes)
|
|
297
|
+
|
|
298
|
+
### 3.5 Alerting Rules — Examples
|
|
299
|
+
|
|
300
|
+
```yaml
|
|
301
|
+
# Example: Brute force detection rule (SIEM-agnostic pseudo-config)
|
|
302
|
+
- rule: brute_force_detection
|
|
303
|
+
description: "Detect brute force login attempts"
|
|
304
|
+
condition:
|
|
305
|
+
event_type: "auth.login.failure"
|
|
306
|
+
threshold: 10
|
|
307
|
+
window: "5m"
|
|
308
|
+
group_by: ["sourceIp", "targetUserId"]
|
|
309
|
+
severity: high
|
|
310
|
+
actions:
|
|
311
|
+
- notify: security-team-slack
|
|
312
|
+
- notify: pagerduty-oncall
|
|
313
|
+
- enrich: geoip-lookup
|
|
314
|
+
- auto_respond: block-ip-30m
|
|
315
|
+
|
|
316
|
+
- rule: privilege_escalation
|
|
317
|
+
description: "Detect unauthorized privilege escalation"
|
|
318
|
+
condition:
|
|
319
|
+
event_type: "authz.role.change"
|
|
320
|
+
where: "actor.role != 'admin'"
|
|
321
|
+
severity: critical
|
|
322
|
+
actions:
|
|
323
|
+
- notify: security-team-slack
|
|
324
|
+
- notify: pagerduty-oncall
|
|
325
|
+
- create_incident: true
|
|
326
|
+
|
|
327
|
+
- rule: impossible_travel
|
|
328
|
+
description: "Login from geographically impossible locations"
|
|
329
|
+
condition:
|
|
330
|
+
event_type: "auth.login.success"
|
|
331
|
+
where: "geo_distance(prev_login.location, current.location) / time_diff > 1000 km/h"
|
|
332
|
+
severity: high
|
|
333
|
+
actions:
|
|
334
|
+
- notify: security-team-slack
|
|
335
|
+
- force_mfa: true
|
|
336
|
+
|
|
337
|
+
- rule: off_hours_admin
|
|
338
|
+
description: "Administrative action outside business hours"
|
|
339
|
+
condition:
|
|
340
|
+
event_type: "system.admin.action"
|
|
341
|
+
where: "hour(timestamp) NOT BETWEEN 6 AND 22"
|
|
342
|
+
severity: medium
|
|
343
|
+
actions:
|
|
344
|
+
- notify: security-team-slack
|
|
345
|
+
|
|
346
|
+
- rule: data_exfiltration
|
|
347
|
+
description: "Unusually large data export"
|
|
348
|
+
condition:
|
|
349
|
+
event_type: "data.export"
|
|
350
|
+
where: "record_count > baseline_avg * 10"
|
|
351
|
+
severity: critical
|
|
352
|
+
actions:
|
|
353
|
+
- notify: security-team-slack
|
|
354
|
+
- notify: pagerduty-oncall
|
|
355
|
+
- auto_respond: suspend-api-key
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### 3.6 Correlation IDs
|
|
359
|
+
|
|
360
|
+
Every request entering the system should receive a unique correlation ID that propagates through
|
|
361
|
+
all downstream service calls. This enables reconstructing the full request path during incident
|
|
362
|
+
investigation.
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
// Middleware: Assign or propagate correlation ID
|
|
366
|
+
function correlationMiddleware(req: Request, res: Response, next: NextFunction): void {
|
|
367
|
+
const correlationId = req.headers['x-correlation-id'] as string
|
|
368
|
+
|| req.headers['x-request-id'] as string
|
|
369
|
+
|| crypto.randomUUID();
|
|
370
|
+
|
|
371
|
+
req.correlationId = correlationId;
|
|
372
|
+
res.setHeader('x-correlation-id', correlationId);
|
|
373
|
+
|
|
374
|
+
// Attach to async context for automatic propagation
|
|
375
|
+
asyncLocalStorage.run({ correlationId }, () => next());
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### 3.7 Honeypots and Canary Tokens
|
|
380
|
+
|
|
381
|
+
Deception technology creates high-fidelity detection signals with near-zero false positive rates.
|
|
382
|
+
|
|
383
|
+
**Canary tokens (Thinkst Canary):**
|
|
384
|
+
- Embed tripwire files in sensitive directories (fake AWS credentials, documents)
|
|
385
|
+
- Any access triggers an immediate alert — legitimate users have no reason to touch them
|
|
386
|
+
- Zero infrastructure overhead, no tuning required
|
|
387
|
+
- Types: DNS tokens, HTTP tokens, document tokens, AWS key tokens, SQL tokens
|
|
388
|
+
|
|
389
|
+
**Application-level honeypots:**
|
|
390
|
+
```typescript
|
|
391
|
+
// Honey endpoint — no legitimate user should ever call this
|
|
392
|
+
app.all('/admin/debug/console', (req, res) => {
|
|
393
|
+
securityLogger.critical({
|
|
394
|
+
event: 'honeypot.triggered',
|
|
395
|
+
path: '/admin/debug/console',
|
|
396
|
+
sourceIp: req.ip,
|
|
397
|
+
headers: sanitizeHeaders(req.headers),
|
|
398
|
+
correlationId: req.correlationId,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Alert immediately — this is ALWAYS malicious
|
|
402
|
+
alertSecurityTeam('HONEYPOT TRIGGERED', { ip: req.ip, path: req.path });
|
|
403
|
+
|
|
404
|
+
// Return believable response to keep attacker engaged
|
|
405
|
+
res.status(403).json({ error: 'Insufficient privileges' });
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Honey database record — triggers alert when queried
|
|
409
|
+
// Insert fake admin account "sysadmin_backup" that no real query should ever retrieve
|
|
410
|
+
// Monitor: SELECT queries returning this record indicate unauthorized data access
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## 4. Vulnerability Catalog
|
|
416
|
+
|
|
417
|
+
### V1: No Authentication Event Logging
|
|
418
|
+
|
|
419
|
+
**CWE-778: Insufficient Logging**
|
|
420
|
+
**Severity: HIGH**
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
// VULNERABLE: No logging of authentication events
|
|
424
|
+
async function login(username: string, password: string): Promise<User> {
|
|
425
|
+
const user = await db.findUser(username);
|
|
426
|
+
if (!user || !await bcrypt.compare(password, user.passwordHash)) {
|
|
427
|
+
throw new UnauthorizedError('Invalid credentials');
|
|
428
|
+
}
|
|
429
|
+
return user;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// SECURE: Comprehensive authentication logging
|
|
433
|
+
async function login(username: string, password: string, req: Request): Promise<User> {
|
|
434
|
+
const user = await db.findUser(username);
|
|
435
|
+
if (!user) {
|
|
436
|
+
securityLogger.warn({
|
|
437
|
+
event: SecurityEventType.AUTH_LOGIN_FAILURE,
|
|
438
|
+
reason: 'user_not_found',
|
|
439
|
+
attemptedUsername: username, // OK to log username for failed lookups
|
|
440
|
+
sourceIp: req.ip,
|
|
441
|
+
userAgent: req.headers['user-agent'],
|
|
442
|
+
correlationId: req.correlationId,
|
|
443
|
+
});
|
|
444
|
+
throw new UnauthorizedError('Invalid credentials');
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (!await bcrypt.compare(password, user.passwordHash)) {
|
|
448
|
+
securityLogger.warn({
|
|
449
|
+
event: SecurityEventType.AUTH_LOGIN_FAILURE,
|
|
450
|
+
reason: 'invalid_password',
|
|
451
|
+
userId: user.id, // Log user ID, NOT the attempted password
|
|
452
|
+
sourceIp: req.ip,
|
|
453
|
+
userAgent: req.headers['user-agent'],
|
|
454
|
+
correlationId: req.correlationId,
|
|
455
|
+
failedAttempts: user.failedLoginAttempts + 1,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
await db.incrementFailedAttempts(user.id);
|
|
459
|
+
if (user.failedLoginAttempts + 1 >= MAX_ATTEMPTS) {
|
|
460
|
+
await db.lockAccount(user.id);
|
|
461
|
+
securityLogger.warn({
|
|
462
|
+
event: SecurityEventType.AUTH_ACCOUNT_LOCKED,
|
|
463
|
+
userId: user.id,
|
|
464
|
+
sourceIp: req.ip,
|
|
465
|
+
correlationId: req.correlationId,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
throw new UnauthorizedError('Invalid credentials');
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
securityLogger.info({
|
|
472
|
+
event: SecurityEventType.AUTH_LOGIN_SUCCESS,
|
|
473
|
+
userId: user.id,
|
|
474
|
+
sourceIp: req.ip,
|
|
475
|
+
userAgent: req.headers['user-agent'],
|
|
476
|
+
correlationId: req.correlationId,
|
|
477
|
+
mfaUsed: false,
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
return user;
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### V2: PII / Sensitive Data in Logs
|
|
485
|
+
|
|
486
|
+
**CWE-532: Insertion of Sensitive Information into Log File**
|
|
487
|
+
**Severity: HIGH**
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
// VULNERABLE: Logging sensitive data
|
|
491
|
+
logger.info(`User registered: ${JSON.stringify(user)}`);
|
|
492
|
+
// Logs: {"name":"John","email":"john@example.com","ssn":"123-45-6789","password":"secret"}
|
|
493
|
+
|
|
494
|
+
logger.debug(`Payment processed: card=${cardNumber}, amount=${amount}`);
|
|
495
|
+
// Logs full credit card number — PCI-DSS violation
|
|
496
|
+
|
|
497
|
+
logger.error(`Auth failed for token: ${authToken}`);
|
|
498
|
+
// Logs the authentication token — attacker reading logs gains access
|
|
499
|
+
|
|
500
|
+
// SECURE: Sanitized logging with PII redaction
|
|
501
|
+
logger.info({
|
|
502
|
+
event: 'user.registered',
|
|
503
|
+
userId: user.id,
|
|
504
|
+
email: maskEmail(user.email), // j***@e***.com
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
logger.info({
|
|
508
|
+
event: 'payment.processed',
|
|
509
|
+
userId: user.id,
|
|
510
|
+
cardLast4: cardNumber.slice(-4), // Only last 4 digits
|
|
511
|
+
amount: amount,
|
|
512
|
+
currency: 'USD',
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### V3: Log Injection (CWE-117)
|
|
517
|
+
|
|
518
|
+
**CWE-117: Improper Output Neutralization for Logs**
|
|
519
|
+
**Severity: MEDIUM**
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
// VULNERABLE: Log injection via CRLF
|
|
523
|
+
const username = req.body.username;
|
|
524
|
+
logger.info(`Login attempt for user: ${username}`);
|
|
525
|
+
// Attacker sends: "admin\n2026-03-08 INFO Login successful for user: admin"
|
|
526
|
+
// Forges a fake "successful login" log entry
|
|
527
|
+
|
|
528
|
+
// VULNERABLE: Log injection via format strings
|
|
529
|
+
logger.info(`Search query: ${userInput}`);
|
|
530
|
+
// Attacker sends input containing format specifiers or control characters
|
|
531
|
+
|
|
532
|
+
// SECURE: Structured logging prevents injection
|
|
533
|
+
logger.info({
|
|
534
|
+
event: 'auth.login.attempt',
|
|
535
|
+
username: username, // JSON serialization escapes \n, \r, etc.
|
|
536
|
+
sourceIp: req.ip,
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// SECURE: Explicit sanitization for text loggers
|
|
540
|
+
function sanitizeForLog(input: string): string {
|
|
541
|
+
return input
|
|
542
|
+
.replace(/[\r\n]/g, ' ') // Remove CRLF
|
|
543
|
+
.replace(/[\x00-\x1f\x7f]/g, '') // Remove control characters
|
|
544
|
+
.substring(0, 1000); // Limit length
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### V4: Logs Not Centralized
|
|
549
|
+
|
|
550
|
+
**Severity: HIGH**
|
|
551
|
+
|
|
552
|
+
When logs exist only on application servers, a compromised server means compromised logs.
|
|
553
|
+
Attackers routinely clear local logs (MITRE ATT&CK T1070.001) to cover their tracks.
|
|
554
|
+
|
|
555
|
+
**Impact:** Complete loss of forensic evidence after system compromise.
|
|
556
|
+
**Fix:** Ship logs in real time via Fluentd/Fluent Bit/Filebeat to a centralized system
|
|
557
|
+
with separate access controls.
|
|
558
|
+
|
|
559
|
+
### V5: No Alerting on Security Events
|
|
560
|
+
|
|
561
|
+
**Severity: CRITICAL**
|
|
562
|
+
|
|
563
|
+
Logs without alerts are forensic-only — useful after the breach, not during it.
|
|
564
|
+
The Equifax breach went undetected for 76 days despite logs existing.
|
|
565
|
+
|
|
566
|
+
**Fix:** Define alert rules for all critical security events. Test alerts regularly.
|
|
567
|
+
Ensure the alerting pipeline is monitored for failures.
|
|
568
|
+
|
|
569
|
+
### V6: Insufficient Log Retention
|
|
570
|
+
|
|
571
|
+
**Severity: MEDIUM**
|
|
572
|
+
|
|
573
|
+
If logs are rotated before an investigation begins, evidence is permanently lost.
|
|
574
|
+
The average breach takes 194 days to detect — 30-day log retention means 164 days of lost data.
|
|
575
|
+
|
|
576
|
+
**Fix:** Retain logs for at least 12 months (PCI-DSS) with 90 days immediately searchable.
|
|
577
|
+
Archive older logs to cold storage (S3 Glacier, GCS Coldline).
|
|
578
|
+
|
|
579
|
+
### V7: Log Tampering Possible
|
|
580
|
+
|
|
581
|
+
**Severity: HIGH**
|
|
582
|
+
|
|
583
|
+
If application processes can delete or modify their own logs, so can an attacker who
|
|
584
|
+
compromises the application.
|
|
585
|
+
|
|
586
|
+
**Fix:** Write logs to append-only storage. Use separate credentials for log writing
|
|
587
|
+
vs. log deletion. Enable log file integrity monitoring (AIDE, OSSEC, Tripwire).
|
|
588
|
+
|
|
589
|
+
### V8: Missing Correlation IDs
|
|
590
|
+
|
|
591
|
+
**Severity: MEDIUM**
|
|
592
|
+
|
|
593
|
+
Without correlation IDs, it is impossible to trace a single request across multiple
|
|
594
|
+
microservices during incident investigation.
|
|
595
|
+
|
|
596
|
+
**Fix:** Generate a UUID at the API gateway / entry point. Propagate via
|
|
597
|
+
`X-Correlation-ID` header. Include in every log entry.
|
|
598
|
+
|
|
599
|
+
### V9: Verbose Error Logging Exposing Internals
|
|
600
|
+
|
|
601
|
+
**CWE-209: Generation of Error Message Containing Sensitive Information**
|
|
602
|
+
**Severity: MEDIUM**
|
|
603
|
+
|
|
604
|
+
```typescript
|
|
605
|
+
// VULNERABLE: Stack trace with internals exposed in logs accessible to monitoring
|
|
606
|
+
logger.error(`Database error: ${err.stack}`);
|
|
607
|
+
// May contain: connection strings, table names, query parameters, file paths
|
|
608
|
+
|
|
609
|
+
// SECURE: Structured error logging with controlled detail
|
|
610
|
+
logger.error({
|
|
611
|
+
event: 'system.error',
|
|
612
|
+
errorCode: 'DB_CONNECTION_FAILED',
|
|
613
|
+
errorMessage: err.message, // Generic message only
|
|
614
|
+
correlationId: req.correlationId,
|
|
615
|
+
// Store full stack trace only in secure, access-controlled debug logs
|
|
616
|
+
});
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### V10: No Rate Limit Monitoring
|
|
620
|
+
|
|
621
|
+
**Severity: MEDIUM**
|
|
622
|
+
|
|
623
|
+
API rate limiting without logging means brute force and enumeration attacks go unnoticed.
|
|
624
|
+
|
|
625
|
+
**Fix:** Log every rate limit event. Alert when a single source triggers rate limits
|
|
626
|
+
across multiple endpoints (reconnaissance pattern).
|
|
627
|
+
|
|
628
|
+
### V11: Clock Skew Between Systems
|
|
629
|
+
|
|
630
|
+
**Severity: MEDIUM**
|
|
631
|
+
|
|
632
|
+
If servers have unsynchronized clocks, log correlation becomes unreliable.
|
|
633
|
+
Event ordering during incident reconstruction fails.
|
|
634
|
+
|
|
635
|
+
**Fix:** Use NTP on all systems. Log timestamps in UTC ISO 8601 format.
|
|
636
|
+
Monitor NTP drift — alert if skew exceeds 1 second.
|
|
637
|
+
|
|
638
|
+
### V12: Logging Disabled in Production
|
|
639
|
+
|
|
640
|
+
**Severity: CRITICAL**
|
|
641
|
+
|
|
642
|
+
Some teams disable debug/info logging in production for performance, inadvertently
|
|
643
|
+
disabling security event logging.
|
|
644
|
+
|
|
645
|
+
**Fix:** Use log levels correctly. Security events should be INFO or WARN level,
|
|
646
|
+
never DEBUG. Security logging must never be disabled regardless of environment.
|
|
647
|
+
|
|
648
|
+
### V13: No Monitoring of the Monitoring System
|
|
649
|
+
|
|
650
|
+
**Severity: HIGH**
|
|
651
|
+
|
|
652
|
+
The Equifax breach demonstrates this perfectly — when the monitoring tool fails,
|
|
653
|
+
no one notices.
|
|
654
|
+
|
|
655
|
+
**Fix:** Implement heartbeat monitoring for log pipelines. Alert when expected
|
|
656
|
+
log volume drops below threshold (dead man's switch / watchdog timer).
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
660
|
+
## 5. Security Checklist
|
|
661
|
+
|
|
662
|
+
### Logging Configuration
|
|
663
|
+
- [ ] All authentication events logged (success, failure, lockout, MFA)
|
|
664
|
+
- [ ] All authorization failures logged with user context
|
|
665
|
+
- [ ] All administrative actions logged with before/after state
|
|
666
|
+
- [ ] Input validation failures logged (including suspected attack payloads, sanitized)
|
|
667
|
+
- [ ] System lifecycle events logged (startup, shutdown, config changes)
|
|
668
|
+
- [ ] API rate limit events logged
|
|
669
|
+
- [ ] Data access to sensitive resources logged
|
|
670
|
+
- [ ] Structured JSON format used (not unstructured text)
|
|
671
|
+
- [ ] Correlation IDs assigned at entry point and propagated
|
|
672
|
+
|
|
673
|
+
### Data Protection
|
|
674
|
+
- [ ] No passwords, tokens, or API keys in logs (verified by automated scan)
|
|
675
|
+
- [ ] No PII in logs without masking (email, SSN, phone, address)
|
|
676
|
+
- [ ] No credit card numbers in logs (PCI-DSS violation)
|
|
677
|
+
- [ ] Log sanitization applied to all user-controlled input (CWE-117 prevention)
|
|
678
|
+
- [ ] Error messages do not expose stack traces or internal paths
|
|
679
|
+
|
|
680
|
+
### Infrastructure
|
|
681
|
+
- [ ] Logs shipped to centralized system in real time (not local-only)
|
|
682
|
+
- [ ] Log transport encrypted (TLS)
|
|
683
|
+
- [ ] Log storage uses append-only / immutable configuration
|
|
684
|
+
- [ ] Log access restricted to authorized personnel only (separate from app admin)
|
|
685
|
+
- [ ] Time synchronization (NTP) configured on all systems
|
|
686
|
+
- [ ] Log pipeline monitored for failures (dead man's switch)
|
|
687
|
+
|
|
688
|
+
### Alerting & Response
|
|
689
|
+
- [ ] Alerting rules defined for brute force, privilege escalation, data exfiltration
|
|
690
|
+
- [ ] Alert escalation path defined (Slack -> PagerDuty -> phone)
|
|
691
|
+
- [ ] Alerts tested regularly (at least monthly)
|
|
692
|
+
- [ ] False positive rate tracked and alert rules tuned quarterly
|
|
693
|
+
- [ ] Honeypot endpoints / canary tokens deployed
|
|
694
|
+
|
|
695
|
+
### Compliance & Retention
|
|
696
|
+
- [ ] Log retention meets regulatory requirements (12 months for PCI-DSS)
|
|
697
|
+
- [ ] 90 days of logs immediately searchable
|
|
698
|
+
- [ ] Log archival to cold storage configured with lifecycle policies
|
|
699
|
+
- [ ] Log access audit trail maintained (who accessed which logs)
|
|
700
|
+
- [ ] Compliance dashboard showing logging coverage gaps
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
## 6. Tools & Automation
|
|
705
|
+
|
|
706
|
+
### SIEM & Log Management
|
|
707
|
+
|
|
708
|
+
| Tool | Type | Key Features |
|
|
709
|
+
|------|------|-------------|
|
|
710
|
+
| **Splunk Enterprise** | Commercial SIEM | SPL query language, 1000+ apps, ML Toolkit |
|
|
711
|
+
| **Microsoft Sentinel** | Cloud SIEM | Native Azure/M365, KQL, built-in SOAR, threat intelligence |
|
|
712
|
+
| **Elastic SIEM** | Open-core SIEM | ECS schema, prebuilt detection rules, ML anomaly detection |
|
|
713
|
+
| **Google Chronicle** | Cloud SIEM | Petabyte-scale, YARA-L, VirusTotal integration |
|
|
714
|
+
| **Datadog Security** | Cloud monitoring | APM + Security unified, cloud-native, real-time |
|
|
715
|
+
|
|
716
|
+
### Log Shippers & Aggregators
|
|
717
|
+
|
|
718
|
+
| Tool | Language | Best For |
|
|
719
|
+
|------|----------|----------|
|
|
720
|
+
| **Fluentd** | Ruby/C | Kubernetes-native, CNCF graduated, plugin ecosystem |
|
|
721
|
+
| **Fluent Bit** | C | Lightweight, embedded/edge, low resource usage |
|
|
722
|
+
| **Filebeat** | Go | Elastic ecosystem, lightweight, modules for common apps |
|
|
723
|
+
| **Vector** | Rust | High performance, observability pipelines, transform capabilities |
|
|
724
|
+
| **AWS CloudWatch Agent** | Go | AWS-native, unified metrics + logs |
|
|
725
|
+
|
|
726
|
+
### Cloud-Native Security Logging
|
|
727
|
+
|
|
728
|
+
**AWS:**
|
|
729
|
+
- **CloudTrail** — API activity logging for all AWS services
|
|
730
|
+
- **GuardDuty** — ML-based threat detection analyzing CloudTrail, VPC Flow Logs, DNS logs
|
|
731
|
+
- **CloudWatch Logs** — Centralized log storage with Insights query language
|
|
732
|
+
- **Security Hub** — Aggregates findings from GuardDuty, Inspector, Macie
|
|
733
|
+
- **Config** — Resource configuration change logging and compliance
|
|
734
|
+
|
|
735
|
+
**GCP:**
|
|
736
|
+
- **Cloud Audit Logs** — Admin activity, data access, system event, policy denied logs
|
|
737
|
+
- **Security Command Center (SCC)** — Centralized security and risk management
|
|
738
|
+
- **Cloud Logging** — Centralized log storage with query language
|
|
739
|
+
- **Chronicle** — Enterprise-scale SIEM
|
|
740
|
+
|
|
741
|
+
**Azure:**
|
|
742
|
+
- **Azure Monitor Logs** — Centralized log analytics with KQL
|
|
743
|
+
- **Microsoft Sentinel** — Cloud-native SIEM + SOAR
|
|
744
|
+
- **Azure Activity Log** — Subscription-level operation logging
|
|
745
|
+
- **Defender for Cloud** — Unified security management
|
|
746
|
+
|
|
747
|
+
### Runtime Security & Host-Based Detection
|
|
748
|
+
|
|
749
|
+
| Tool | Type | Key Features |
|
|
750
|
+
|------|------|-------------|
|
|
751
|
+
| **Falco** | Runtime security | eBPF-based, CNCF incubating, Kubernetes-native, syscall monitoring |
|
|
752
|
+
| **OSSEC** | HIDS | Log analysis, file integrity, rootkit detection, active response |
|
|
753
|
+
| **Wazuh** | XDR/SIEM | OSSEC fork, container security, compliance dashboards, Kubernetes audit |
|
|
754
|
+
| **Osquery** | Endpoint | SQL-based system queries, fleet management |
|
|
755
|
+
|
|
756
|
+
### Deception Technology
|
|
757
|
+
|
|
758
|
+
| Tool | Type | Key Features |
|
|
759
|
+
|------|------|-------------|
|
|
760
|
+
| **Thinkst Canary** | Honeypot platform | Hardware/cloud canaries, canarytokens.org (free), near-zero FP rate |
|
|
761
|
+
| **Canarytokens.org** | Free canary tokens | DNS, HTTP, AWS key, document, SQL tokens |
|
|
762
|
+
|
|
763
|
+
---
|
|
764
|
+
|
|
765
|
+
## 7. Platform-Specific Guidance
|
|
766
|
+
|
|
767
|
+
### 7.1 Node.js — Pino (Recommended for Performance)
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
import pino from 'pino';
|
|
771
|
+
|
|
772
|
+
// Production security logger configuration
|
|
773
|
+
const securityLogger = pino({
|
|
774
|
+
name: 'security',
|
|
775
|
+
level: 'info',
|
|
776
|
+
// JSON output by default (NDJSON)
|
|
777
|
+
formatters: {
|
|
778
|
+
level(label: string) {
|
|
779
|
+
return { level: label }; // Use string labels, not numeric levels
|
|
780
|
+
},
|
|
781
|
+
},
|
|
782
|
+
// Redact sensitive fields automatically
|
|
783
|
+
redact: {
|
|
784
|
+
paths: [
|
|
785
|
+
'req.headers.authorization',
|
|
786
|
+
'req.headers.cookie',
|
|
787
|
+
'password',
|
|
788
|
+
'token',
|
|
789
|
+
'secret',
|
|
790
|
+
'apiKey',
|
|
791
|
+
'creditCard',
|
|
792
|
+
'ssn',
|
|
793
|
+
],
|
|
794
|
+
censor: '[REDACTED]',
|
|
795
|
+
},
|
|
796
|
+
// Serializers for consistent formatting
|
|
797
|
+
serializers: {
|
|
798
|
+
req: pino.stdSerializers.req,
|
|
799
|
+
err: pino.stdSerializers.err,
|
|
800
|
+
},
|
|
801
|
+
// Ship to centralized logging
|
|
802
|
+
transport: {
|
|
803
|
+
targets: [
|
|
804
|
+
{
|
|
805
|
+
target: 'pino/file',
|
|
806
|
+
options: { destination: '/var/log/app/security.log' },
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
target: 'pino-socket', // Real-time log shipping
|
|
810
|
+
options: { address: 'logstash.internal', port: 5044, mode: 'tcp' },
|
|
811
|
+
},
|
|
812
|
+
],
|
|
813
|
+
},
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
// Usage with child loggers for context propagation
|
|
817
|
+
function createRequestLogger(req: Request): pino.Logger {
|
|
818
|
+
return securityLogger.child({
|
|
819
|
+
correlationId: req.correlationId,
|
|
820
|
+
sourceIp: req.ip,
|
|
821
|
+
userAgent: req.headers['user-agent'],
|
|
822
|
+
userId: req.user?.id,
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
### 7.2 Node.js — Winston (Recommended for Flexibility)
|
|
828
|
+
|
|
829
|
+
```typescript
|
|
830
|
+
import winston from 'winston';
|
|
831
|
+
|
|
832
|
+
const securityLogger = winston.createLogger({
|
|
833
|
+
level: 'info',
|
|
834
|
+
format: winston.format.combine(
|
|
835
|
+
winston.format.timestamp({ format: 'YYYY-MM-DDTHH:mm:ss.SSSZ' }),
|
|
836
|
+
winston.format.errors({ stack: false }), // No stack traces in security logs
|
|
837
|
+
winston.format.json(),
|
|
838
|
+
),
|
|
839
|
+
defaultMeta: {
|
|
840
|
+
service: 'auth-service',
|
|
841
|
+
environment: process.env.NODE_ENV,
|
|
842
|
+
},
|
|
843
|
+
transports: [
|
|
844
|
+
// Local file (backup)
|
|
845
|
+
new winston.transports.File({
|
|
846
|
+
filename: '/var/log/app/security.log',
|
|
847
|
+
maxsize: 100 * 1024 * 1024, // 100MB rotation
|
|
848
|
+
maxFiles: 10,
|
|
849
|
+
}),
|
|
850
|
+
// Centralized logging (primary)
|
|
851
|
+
new winston.transports.Http({
|
|
852
|
+
host: 'logstash.internal',
|
|
853
|
+
port: 8080,
|
|
854
|
+
ssl: true,
|
|
855
|
+
}),
|
|
856
|
+
],
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
// NEVER log to console in production (performance + potential injection)
|
|
860
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
861
|
+
securityLogger.add(new winston.transports.Console({
|
|
862
|
+
format: winston.format.combine(
|
|
863
|
+
winston.format.colorize(),
|
|
864
|
+
winston.format.simple(),
|
|
865
|
+
),
|
|
866
|
+
}));
|
|
867
|
+
}
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
### 7.3 Python — Standard Logging Module
|
|
871
|
+
|
|
872
|
+
```python
|
|
873
|
+
import logging
|
|
874
|
+
import json
|
|
875
|
+
import re
|
|
876
|
+
from datetime import datetime, timezone
|
|
877
|
+
|
|
878
|
+
class SecurityJsonFormatter(logging.Formatter):
|
|
879
|
+
"""JSON formatter with PII redaction for security logs."""
|
|
880
|
+
|
|
881
|
+
PII_PATTERNS = {
|
|
882
|
+
'email': re.compile(r'[\w.-]+@[\w.-]+\.\w+'),
|
|
883
|
+
'ssn': re.compile(r'\b\d{3}-\d{2}-\d{4}\b'),
|
|
884
|
+
'credit_card': re.compile(r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b'),
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
888
|
+
log_entry = {
|
|
889
|
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
|
890
|
+
'level': record.levelname,
|
|
891
|
+
'event': getattr(record, 'event', record.msg),
|
|
892
|
+
'logger': record.name,
|
|
893
|
+
'correlation_id': getattr(record, 'correlation_id', None),
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
# Merge extra fields
|
|
897
|
+
if hasattr(record, 'security_context'):
|
|
898
|
+
log_entry.update(record.security_context)
|
|
899
|
+
|
|
900
|
+
# Sanitize all string values
|
|
901
|
+
log_entry = self._sanitize(log_entry)
|
|
902
|
+
return json.dumps(log_entry, default=str)
|
|
903
|
+
|
|
904
|
+
def _sanitize(self, data: dict) -> dict:
|
|
905
|
+
sanitized = {}
|
|
906
|
+
for key, value in data.items():
|
|
907
|
+
if isinstance(value, str):
|
|
908
|
+
for pii_type, pattern in self.PII_PATTERNS.items():
|
|
909
|
+
value = pattern.sub(f'[REDACTED-{pii_type.upper()}]', value)
|
|
910
|
+
elif isinstance(value, dict):
|
|
911
|
+
value = self._sanitize(value)
|
|
912
|
+
sanitized[key] = value
|
|
913
|
+
return sanitized
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
# Configuration
|
|
917
|
+
security_logger = logging.getLogger('security')
|
|
918
|
+
security_logger.setLevel(logging.INFO)
|
|
919
|
+
|
|
920
|
+
handler = logging.FileHandler('/var/log/app/security.log')
|
|
921
|
+
handler.setFormatter(SecurityJsonFormatter())
|
|
922
|
+
security_logger.addHandler(handler)
|
|
923
|
+
|
|
924
|
+
# Usage
|
|
925
|
+
security_logger.info(
|
|
926
|
+
'auth.login.success',
|
|
927
|
+
extra={
|
|
928
|
+
'event': 'auth.login.success',
|
|
929
|
+
'correlation_id': request_id,
|
|
930
|
+
'security_context': {
|
|
931
|
+
'user_id': user.id,
|
|
932
|
+
'source_ip': request.remote_addr,
|
|
933
|
+
'mfa_used': True,
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
)
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
### 7.4 Kubernetes Logging
|
|
940
|
+
|
|
941
|
+
```yaml
|
|
942
|
+
# Kubernetes audit policy — log security-relevant API server events
|
|
943
|
+
apiVersion: audit.k8s.io/v1
|
|
944
|
+
kind: Policy
|
|
945
|
+
rules:
|
|
946
|
+
# Log all authentication failures at RequestResponse level
|
|
947
|
+
- level: RequestResponse
|
|
948
|
+
users: ["system:anonymous"]
|
|
949
|
+
resources:
|
|
950
|
+
- group: ""
|
|
951
|
+
resources: ["*"]
|
|
952
|
+
|
|
953
|
+
# Log all changes to RBAC resources
|
|
954
|
+
- level: RequestResponse
|
|
955
|
+
verbs: ["create", "update", "patch", "delete"]
|
|
956
|
+
resources:
|
|
957
|
+
- group: "rbac.authorization.k8s.io"
|
|
958
|
+
resources: ["clusterroles", "clusterrolebindings", "roles", "rolebindings"]
|
|
959
|
+
|
|
960
|
+
# Log Secret access
|
|
961
|
+
- level: Metadata
|
|
962
|
+
resources:
|
|
963
|
+
- group: ""
|
|
964
|
+
resources: ["secrets"]
|
|
965
|
+
|
|
966
|
+
# Log pod exec (potential container escape)
|
|
967
|
+
- level: RequestResponse
|
|
968
|
+
resources:
|
|
969
|
+
- group: ""
|
|
970
|
+
resources: ["pods/exec", "pods/attach"]
|
|
971
|
+
|
|
972
|
+
# Log service account token requests
|
|
973
|
+
- level: Metadata
|
|
974
|
+
resources:
|
|
975
|
+
- group: ""
|
|
976
|
+
resources: ["serviceaccounts/token"]
|
|
977
|
+
|
|
978
|
+
# Default: log metadata for all other requests
|
|
979
|
+
- level: Metadata
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
```yaml
|
|
983
|
+
# Falco rule — detect sensitive file access in containers
|
|
984
|
+
- rule: Read sensitive file in container
|
|
985
|
+
desc: Detect reading of sensitive files within a container
|
|
986
|
+
condition: >
|
|
987
|
+
open_read and container and
|
|
988
|
+
(fd.name startswith /etc/shadow or
|
|
989
|
+
fd.name startswith /etc/passwd or
|
|
990
|
+
fd.name startswith /root/.ssh or
|
|
991
|
+
fd.name startswith /run/secrets)
|
|
992
|
+
output: >
|
|
993
|
+
Sensitive file read in container
|
|
994
|
+
(user=%user.name file=%fd.name container=%container.name
|
|
995
|
+
image=%container.image.repository command=%proc.cmdline)
|
|
996
|
+
priority: WARNING
|
|
997
|
+
tags: [filesystem, mitre_credential_access]
|
|
998
|
+
|
|
999
|
+
- rule: Unexpected outbound connection
|
|
1000
|
+
desc: Detect unexpected outbound network connections from containers
|
|
1001
|
+
condition: >
|
|
1002
|
+
outbound and container and
|
|
1003
|
+
not (fd.sport in (80, 443, 53, 8080, 8443)) and
|
|
1004
|
+
not proc.name in (allowed_outbound_procs)
|
|
1005
|
+
output: >
|
|
1006
|
+
Unexpected outbound connection from container
|
|
1007
|
+
(user=%user.name command=%proc.cmdline connection=%fd.name
|
|
1008
|
+
container=%container.name image=%container.image.repository)
|
|
1009
|
+
priority: NOTICE
|
|
1010
|
+
tags: [network, mitre_exfiltration]
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
### 7.5 Container Logging Best Practices
|
|
1014
|
+
|
|
1015
|
+
- Log to **stdout/stderr** (not files) — let the container runtime handle collection
|
|
1016
|
+
- Use a **sidecar pattern** or **DaemonSet** (Fluent Bit) for log collection
|
|
1017
|
+
- Include **container metadata** in every log entry (pod name, namespace, image, node)
|
|
1018
|
+
- Set log **size limits** to prevent disk exhaustion attacks via log flooding
|
|
1019
|
+
- Never store secrets in container environment variables that get logged on crash
|
|
1020
|
+
|
|
1021
|
+
---
|
|
1022
|
+
|
|
1023
|
+
## 8. Incident Patterns — Log-Based Detection
|
|
1024
|
+
|
|
1025
|
+
### 8.1 Attack Timeline Reconstruction
|
|
1026
|
+
|
|
1027
|
+
When investigating a security incident, logs enable building a forensic timeline.
|
|
1028
|
+
|
|
1029
|
+
**Reconstruction process:**
|
|
1030
|
+
1. **Identify the indicator** — Alert trigger, anomalous event, or external report
|
|
1031
|
+
2. **Establish pivot points** — Find the correlation ID, user ID, source IP, or session
|
|
1032
|
+
3. **Expand the timeline** — Search for all events from that pivot in a +/- 24h window
|
|
1033
|
+
4. **Trace lateral movement** — Follow the actor across systems via correlation IDs
|
|
1034
|
+
5. **Identify the entry point** — Work backward from the first malicious action
|
|
1035
|
+
6. **Determine scope** — What data/systems were accessed during the attack window
|
|
1036
|
+
7. **Establish containment** — Verify no further malicious activity after response
|
|
1037
|
+
|
|
1038
|
+
```
|
|
1039
|
+
# Example: Reconstructing a credential stuffing attack
|
|
1040
|
+
|
|
1041
|
+
# Step 1: Alert fires — brute force detection
|
|
1042
|
+
2026-03-08T14:32:00Z ALERT brute_force_detection sourceIp=203.0.113.42 failures=47 window=5m
|
|
1043
|
+
|
|
1044
|
+
# Step 2: Pivot on source IP — show all activity
|
|
1045
|
+
2026-03-08T14:28:12Z auth.login.failure userId=1042 sourceIp=203.0.113.42
|
|
1046
|
+
2026-03-08T14:28:13Z auth.login.failure userId=8391 sourceIp=203.0.113.42
|
|
1047
|
+
... (45 more failures across different userIds)
|
|
1048
|
+
2026-03-08T14:31:44Z auth.login.success userId=5573 sourceIp=203.0.113.42 # <-- BREACH
|
|
1049
|
+
2026-03-08T14:31:45Z auth.login.success userId=12904 sourceIp=203.0.113.42 # <-- BREACH
|
|
1050
|
+
|
|
1051
|
+
# Step 3: Pivot on compromised users — what did they do?
|
|
1052
|
+
2026-03-08T14:31:50Z data.read.sensitive userId=5573 resource=/api/profile
|
|
1053
|
+
2026-03-08T14:31:52Z auth.password.change userId=5573 sourceIp=203.0.113.42 # Persistence
|
|
1054
|
+
2026-03-08T14:32:01Z data.export userId=5573 resource=/api/transactions count=2847
|
|
1055
|
+
|
|
1056
|
+
# Step 4: Scope — 2 accounts compromised, 1 had data exported
|
|
1057
|
+
# Step 5: Response — block IP, reset passwords, revoke sessions, notify users
|
|
1058
|
+
```
|
|
1059
|
+
|
|
1060
|
+
### 8.2 Common Detection Patterns
|
|
1061
|
+
|
|
1062
|
+
| Pattern | Indicators in Logs | Severity |
|
|
1063
|
+
|---------|-------------------|----------|
|
|
1064
|
+
| **Credential Stuffing** | Many auth failures across different usernames from same IP | High |
|
|
1065
|
+
| **Account Takeover** | Login success after multiple failures, followed by password change | Critical |
|
|
1066
|
+
| **Privilege Escalation** | Role change or admin action by non-admin user | Critical |
|
|
1067
|
+
| **Data Exfiltration** | Bulk data export, unusual download volume, off-hours access | Critical |
|
|
1068
|
+
| **API Abuse** | Rate limit hits, enumeration patterns, parameter fuzzing | High |
|
|
1069
|
+
| **Insider Threat** | Access to resources outside job function, off-hours bulk access | High |
|
|
1070
|
+
| **Lateral Movement** | Authentication from internal IP not associated with user's workstation | High |
|
|
1071
|
+
| **Reconnaissance** | 404 errors across many paths, sequential resource ID access | Medium |
|
|
1072
|
+
| **Log Tampering** | Log gaps, timestamp inconsistencies, log service restarts | Critical |
|
|
1073
|
+
|
|
1074
|
+
### 8.3 Forensic Log Analysis
|
|
1075
|
+
|
|
1076
|
+
**Key forensic questions logs must answer:**
|
|
1077
|
+
- **Who?** — User ID, service account, API key identity
|
|
1078
|
+
- **What?** — Action performed, resource accessed, data volume
|
|
1079
|
+
- **When?** — Precise timestamp (millisecond resolution, UTC)
|
|
1080
|
+
- **Where?** — Source IP, geographic location, device fingerprint
|
|
1081
|
+
- **How?** — Authentication method, API endpoint, client tool
|
|
1082
|
+
- **Outcome?** — Success/failure, error code, response size
|
|
1083
|
+
|
|
1084
|
+
**Log integrity for legal proceedings:**
|
|
1085
|
+
- Logs may be required as evidence in legal or regulatory proceedings
|
|
1086
|
+
- Chain of custody must be maintained — who accessed logs, when
|
|
1087
|
+
- Hash verification proves logs have not been tampered with
|
|
1088
|
+
- Time synchronization proves event ordering is accurate
|
|
1089
|
+
- Centralized, immutable storage proves completeness
|
|
1090
|
+
|
|
1091
|
+
---
|
|
1092
|
+
|
|
1093
|
+
## 9. Compliance & Standards
|
|
1094
|
+
|
|
1095
|
+
### 9.1 OWASP A09:2021 — Security Logging and Monitoring Failures
|
|
1096
|
+
|
|
1097
|
+
**Requirements:**
|
|
1098
|
+
- All login, access control, and input validation failures logged with sufficient context
|
|
1099
|
+
- Logs generated in a format easily consumed by log management solutions
|
|
1100
|
+
- High-value transactions have audit trail with integrity controls
|
|
1101
|
+
- Effective monitoring and alerting established to detect suspicious activity in timely fashion
|
|
1102
|
+
- Incident response and recovery plan exists
|
|
1103
|
+
|
|
1104
|
+
**Testing guidance:**
|
|
1105
|
+
- Review application for insufficient logging, monitoring, and alerting
|
|
1106
|
+
- Test if log entries include adequate detail to identify attacker activity
|
|
1107
|
+
- Confirm logs are sent to centralized management and not just stored locally
|
|
1108
|
+
|
|
1109
|
+
### 9.2 NIST SP 800-92 — Guide to Computer Security Log Management
|
|
1110
|
+
|
|
1111
|
+
**Key recommendations:**
|
|
1112
|
+
- Establish log management policies defining what to log, retention, and roles
|
|
1113
|
+
- Prioritize log management based on risk assessment
|
|
1114
|
+
- Create and maintain log management infrastructure
|
|
1115
|
+
- Establish standard log management operational processes
|
|
1116
|
+
- Perform log analysis (review, correlation, long-term analysis)
|
|
1117
|
+
- Initial response to identified threats based on log analysis
|
|
1118
|
+
|
|
1119
|
+
NIST SP 800-92 Rev. 1 (2023 draft) adds emphasis on:
|
|
1120
|
+
- Cloud-native logging considerations
|
|
1121
|
+
- Zero trust architecture logging requirements
|
|
1122
|
+
- Automation of log analysis and response
|
|
1123
|
+
- Supply chain log integrity
|
|
1124
|
+
|
|
1125
|
+
### 9.3 PCI-DSS v4.0 Requirement 10
|
|
1126
|
+
|
|
1127
|
+
**Requirement 10: Log and Monitor All Access to System Components and Cardholder Data**
|
|
1128
|
+
|
|
1129
|
+
| Sub-Requirement | Description |
|
|
1130
|
+
|-----------------|-------------|
|
|
1131
|
+
| 10.1 | Processes and mechanisms for logging and monitoring are defined and documented |
|
|
1132
|
+
| 10.2 | Audit logs are implemented to support detection of anomalies and suspicious activity |
|
|
1133
|
+
| 10.3 | Audit logs are protected from destruction and unauthorized modifications |
|
|
1134
|
+
| 10.4 | Audit logs are reviewed to identify anomalies or suspicious activity |
|
|
1135
|
+
| 10.5 | Audit log history is retained and available for analysis |
|
|
1136
|
+
| 10.6 | Time-synchronization mechanisms support consistent time across all systems |
|
|
1137
|
+
| 10.7 | Failures of critical security control systems are detected, reported, and responded to |
|
|
1138
|
+
|
|
1139
|
+
**Specific logging requirements:**
|
|
1140
|
+
- All individual user access to cardholder data
|
|
1141
|
+
- All actions taken by any individual with root or administrative privileges
|
|
1142
|
+
- Access to all audit trails
|
|
1143
|
+
- Invalid logical access attempts
|
|
1144
|
+
- Use of and changes to identification and authentication mechanisms
|
|
1145
|
+
- Initialization, stopping, or pausing of the audit logs
|
|
1146
|
+
- Creation and deletion of system-level objects
|
|
1147
|
+
- Retain audit trail history for at least 12 months, with minimum 3 months immediately available
|
|
1148
|
+
|
|
1149
|
+
### 9.4 SOC 2 Logging Controls
|
|
1150
|
+
|
|
1151
|
+
SOC 2 Trust Service Criteria relevant to logging:
|
|
1152
|
+
|
|
1153
|
+
- **CC6.1** — Logical access security over information assets
|
|
1154
|
+
- **CC6.8** — Controls to prevent or detect unauthorized software
|
|
1155
|
+
- **CC7.1** — Detection and monitoring procedures for new vulnerabilities
|
|
1156
|
+
- **CC7.2** — Monitoring of system components for anomalies
|
|
1157
|
+
- **CC7.3** — Evaluation of security events to determine if they are incidents
|
|
1158
|
+
- **CC7.4** — Incident response procedures
|
|
1159
|
+
|
|
1160
|
+
### 9.5 GDPR Logging Requirements
|
|
1161
|
+
|
|
1162
|
+
GDPR creates a tension between logging (for security) and data minimization (for privacy):
|
|
1163
|
+
|
|
1164
|
+
- **Article 5(1)(f)** — Appropriate security measures including logging
|
|
1165
|
+
- **Article 30** — Records of processing activities
|
|
1166
|
+
- **Article 33** — Breach notification within 72 hours (requires detection capability)
|
|
1167
|
+
- **Article 32** — Ability to restore availability and access to data in timely manner
|
|
1168
|
+
|
|
1169
|
+
**GDPR-compliant logging guidelines:**
|
|
1170
|
+
- Log access to personal data for accountability
|
|
1171
|
+
- Do NOT log personal data content in log messages
|
|
1172
|
+
- Apply retention limits to logs containing personal data identifiers
|
|
1173
|
+
- Document the legal basis for logging (legitimate interest — security)
|
|
1174
|
+
- Include logging in your Records of Processing Activities (ROPA)
|
|
1175
|
+
- Pseudonymize user identifiers in logs where possible
|
|
1176
|
+
|
|
1177
|
+
---
|
|
1178
|
+
|
|
1179
|
+
## 10. Code Examples
|
|
1180
|
+
|
|
1181
|
+
### 10.1 Complete Structured Security Logger (TypeScript)
|
|
1182
|
+
|
|
1183
|
+
```typescript
|
|
1184
|
+
import pino from 'pino';
|
|
1185
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
1186
|
+
|
|
1187
|
+
// Types
|
|
1188
|
+
interface SecurityEvent {
|
|
1189
|
+
event: string;
|
|
1190
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
1191
|
+
userId?: string;
|
|
1192
|
+
sourceIp?: string;
|
|
1193
|
+
resource?: string;
|
|
1194
|
+
outcome: 'success' | 'failure';
|
|
1195
|
+
reason?: string;
|
|
1196
|
+
metadata?: Record<string, unknown>;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
interface RequestContext {
|
|
1200
|
+
correlationId: string;
|
|
1201
|
+
userId?: string;
|
|
1202
|
+
sourceIp?: string;
|
|
1203
|
+
sessionId?: string;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// Async context storage for automatic correlation ID propagation
|
|
1207
|
+
const asyncContext = new AsyncLocalStorage<RequestContext>();
|
|
1208
|
+
|
|
1209
|
+
// PII patterns for automatic redaction
|
|
1210
|
+
const PII_PATTERNS: Record<string, RegExp> = {
|
|
1211
|
+
email: /[\w.-]+@[\w.-]+\.\w+/g,
|
|
1212
|
+
ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
1213
|
+
creditCard: /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,
|
|
1214
|
+
phone: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g,
|
|
1215
|
+
jwt: /eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
|
|
1216
|
+
};
|
|
1217
|
+
|
|
1218
|
+
function redactPII(value: string): string {
|
|
1219
|
+
let redacted = value;
|
|
1220
|
+
for (const [type, pattern] of Object.entries(PII_PATTERNS)) {
|
|
1221
|
+
redacted = redacted.replace(pattern, `[REDACTED:${type}]`);
|
|
1222
|
+
}
|
|
1223
|
+
return redacted;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
function maskEmail(email: string): string {
|
|
1227
|
+
const [local, domain] = email.split('@');
|
|
1228
|
+
if (!domain) return '[INVALID_EMAIL]';
|
|
1229
|
+
return `${local[0]}***@${domain[0]}***.${domain.split('.').pop()}`;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// Create the base logger
|
|
1233
|
+
const baseLogger = pino({
|
|
1234
|
+
name: 'security-audit',
|
|
1235
|
+
level: 'info',
|
|
1236
|
+
redact: {
|
|
1237
|
+
paths: [
|
|
1238
|
+
'password', 'token', 'secret', 'apiKey', 'authorization',
|
|
1239
|
+
'cookie', 'creditCard', 'ssn', 'req.headers.authorization',
|
|
1240
|
+
'req.headers.cookie',
|
|
1241
|
+
],
|
|
1242
|
+
censor: '[REDACTED]',
|
|
1243
|
+
},
|
|
1244
|
+
formatters: {
|
|
1245
|
+
level(label) { return { level: label }; },
|
|
1246
|
+
},
|
|
1247
|
+
timestamp: () => `,"timestamp":"${new Date().toISOString()}"`,
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
// Security logger with context enrichment
|
|
1251
|
+
export const securityLogger = {
|
|
1252
|
+
log(event: SecurityEvent): void {
|
|
1253
|
+
const ctx = asyncContext.getStore();
|
|
1254
|
+
const enrichedEvent = {
|
|
1255
|
+
...event,
|
|
1256
|
+
correlationId: ctx?.correlationId,
|
|
1257
|
+
userId: event.userId || ctx?.userId,
|
|
1258
|
+
sourceIp: event.sourceIp || ctx?.sourceIp,
|
|
1259
|
+
service: process.env.SERVICE_NAME || 'unknown',
|
|
1260
|
+
environment: process.env.NODE_ENV || 'unknown',
|
|
1261
|
+
};
|
|
1262
|
+
|
|
1263
|
+
const level = event.severity === 'critical' || event.severity === 'high'
|
|
1264
|
+
? 'warn' : 'info';
|
|
1265
|
+
|
|
1266
|
+
baseLogger[level](enrichedEvent);
|
|
1267
|
+
},
|
|
1268
|
+
|
|
1269
|
+
authSuccess(userId: string, method: string, mfaUsed: boolean): void {
|
|
1270
|
+
this.log({
|
|
1271
|
+
event: 'auth.login.success',
|
|
1272
|
+
severity: 'low',
|
|
1273
|
+
userId,
|
|
1274
|
+
outcome: 'success',
|
|
1275
|
+
metadata: { method, mfaUsed },
|
|
1276
|
+
});
|
|
1277
|
+
},
|
|
1278
|
+
|
|
1279
|
+
authFailure(userId: string | undefined, reason: string): void {
|
|
1280
|
+
this.log({
|
|
1281
|
+
event: 'auth.login.failure',
|
|
1282
|
+
severity: 'medium',
|
|
1283
|
+
userId,
|
|
1284
|
+
outcome: 'failure',
|
|
1285
|
+
reason,
|
|
1286
|
+
});
|
|
1287
|
+
},
|
|
1288
|
+
|
|
1289
|
+
accessDenied(userId: string, resource: string, action: string): void {
|
|
1290
|
+
this.log({
|
|
1291
|
+
event: 'authz.access.denied',
|
|
1292
|
+
severity: 'high',
|
|
1293
|
+
userId,
|
|
1294
|
+
resource,
|
|
1295
|
+
outcome: 'failure',
|
|
1296
|
+
reason: `unauthorized_${action}`,
|
|
1297
|
+
});
|
|
1298
|
+
},
|
|
1299
|
+
|
|
1300
|
+
dataAccess(userId: string, resource: string, recordCount?: number): void {
|
|
1301
|
+
this.log({
|
|
1302
|
+
event: 'data.access',
|
|
1303
|
+
severity: recordCount && recordCount > 100 ? 'high' : 'low',
|
|
1304
|
+
userId,
|
|
1305
|
+
resource,
|
|
1306
|
+
outcome: 'success',
|
|
1307
|
+
metadata: { recordCount },
|
|
1308
|
+
});
|
|
1309
|
+
},
|
|
1310
|
+
|
|
1311
|
+
adminAction(userId: string, action: string, target: string): void {
|
|
1312
|
+
this.log({
|
|
1313
|
+
event: 'system.admin.action',
|
|
1314
|
+
severity: 'high',
|
|
1315
|
+
userId,
|
|
1316
|
+
outcome: 'success',
|
|
1317
|
+
metadata: { action, target },
|
|
1318
|
+
});
|
|
1319
|
+
},
|
|
1320
|
+
|
|
1321
|
+
honeypotTriggered(path: string): void {
|
|
1322
|
+
this.log({
|
|
1323
|
+
event: 'honeypot.triggered',
|
|
1324
|
+
severity: 'critical',
|
|
1325
|
+
resource: path,
|
|
1326
|
+
outcome: 'failure',
|
|
1327
|
+
reason: 'deception_triggered',
|
|
1328
|
+
});
|
|
1329
|
+
},
|
|
1330
|
+
|
|
1331
|
+
// Expose async context for middleware
|
|
1332
|
+
runWithContext<T>(ctx: RequestContext, fn: () => T): T {
|
|
1333
|
+
return asyncContext.run(ctx, fn);
|
|
1334
|
+
},
|
|
1335
|
+
};
|
|
1336
|
+
```
|
|
1337
|
+
|
|
1338
|
+
### 10.2 Audit Trail Middleware (Express)
|
|
1339
|
+
|
|
1340
|
+
```typescript
|
|
1341
|
+
import { Request, Response, NextFunction } from 'express';
|
|
1342
|
+
import crypto from 'crypto';
|
|
1343
|
+
import { securityLogger } from './security-logger';
|
|
1344
|
+
|
|
1345
|
+
// Assign correlation ID and establish security context
|
|
1346
|
+
export function securityContextMiddleware(
|
|
1347
|
+
req: Request, res: Response, next: NextFunction
|
|
1348
|
+
): void {
|
|
1349
|
+
const correlationId = (req.headers['x-correlation-id'] as string)
|
|
1350
|
+
|| (req.headers['x-request-id'] as string)
|
|
1351
|
+
|| crypto.randomUUID();
|
|
1352
|
+
|
|
1353
|
+
res.setHeader('x-correlation-id', correlationId);
|
|
1354
|
+
|
|
1355
|
+
const ctx = {
|
|
1356
|
+
correlationId,
|
|
1357
|
+
userId: req.user?.id,
|
|
1358
|
+
sourceIp: req.ip || req.socket.remoteAddress || 'unknown',
|
|
1359
|
+
sessionId: req.sessionID,
|
|
1360
|
+
};
|
|
1361
|
+
|
|
1362
|
+
securityLogger.runWithContext(ctx, () => next());
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// Log all requests with security context
|
|
1366
|
+
export function auditTrailMiddleware(
|
|
1367
|
+
req: Request, res: Response, next: NextFunction
|
|
1368
|
+
): void {
|
|
1369
|
+
const startTime = Date.now();
|
|
1370
|
+
|
|
1371
|
+
// Capture response
|
|
1372
|
+
const originalEnd = res.end;
|
|
1373
|
+
res.end = function(...args: any[]) {
|
|
1374
|
+
const duration = Date.now() - startTime;
|
|
1375
|
+
const statusCode = res.statusCode;
|
|
1376
|
+
|
|
1377
|
+
// Log security-relevant requests
|
|
1378
|
+
if (isSecurityRelevant(req, statusCode)) {
|
|
1379
|
+
securityLogger.log({
|
|
1380
|
+
event: 'http.request',
|
|
1381
|
+
severity: statusCode >= 400 ? 'medium' : 'low',
|
|
1382
|
+
userId: req.user?.id,
|
|
1383
|
+
sourceIp: req.ip,
|
|
1384
|
+
resource: `${req.method} ${req.route?.path || req.path}`,
|
|
1385
|
+
outcome: statusCode < 400 ? 'success' : 'failure',
|
|
1386
|
+
metadata: {
|
|
1387
|
+
method: req.method,
|
|
1388
|
+
path: req.path, // Actual path
|
|
1389
|
+
route: req.route?.path, // Route pattern (no params)
|
|
1390
|
+
statusCode,
|
|
1391
|
+
duration,
|
|
1392
|
+
contentLength: res.getHeader('content-length'),
|
|
1393
|
+
userAgent: req.headers['user-agent'],
|
|
1394
|
+
},
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
return originalEnd.apply(res, args);
|
|
1399
|
+
} as any;
|
|
1400
|
+
|
|
1401
|
+
next();
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
function isSecurityRelevant(req: Request, statusCode: number): boolean {
|
|
1405
|
+
// Always log: auth endpoints, admin routes, errors, sensitive data access
|
|
1406
|
+
return (
|
|
1407
|
+
req.path.startsWith('/auth') ||
|
|
1408
|
+
req.path.startsWith('/admin') ||
|
|
1409
|
+
req.path.startsWith('/api/users') ||
|
|
1410
|
+
statusCode === 401 ||
|
|
1411
|
+
statusCode === 403 ||
|
|
1412
|
+
statusCode >= 500 ||
|
|
1413
|
+
req.method !== 'GET' // All mutations
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1416
|
+
```
|
|
1417
|
+
|
|
1418
|
+
### 10.3 Log Sanitization — PII Redaction Middleware
|
|
1419
|
+
|
|
1420
|
+
```typescript
|
|
1421
|
+
import pino from 'pino';
|
|
1422
|
+
|
|
1423
|
+
// Custom Pino transport that redacts PII before writing
|
|
1424
|
+
export function createSanitizingTransport(): pino.TransportSingleOptions {
|
|
1425
|
+
return {
|
|
1426
|
+
target: './pii-redaction-transport',
|
|
1427
|
+
options: {
|
|
1428
|
+
destination: '/var/log/app/security.log',
|
|
1429
|
+
sensitiveKeys: [
|
|
1430
|
+
'password', 'token', 'secret', 'apiKey', 'authorization',
|
|
1431
|
+
'cookie', 'ssn', 'creditCard', 'dateOfBirth',
|
|
1432
|
+
],
|
|
1433
|
+
piiPatterns: {
|
|
1434
|
+
email: { pattern: '[\\w.-]+@[\\w.-]+\\.\\w+', replacement: '[EMAIL]' },
|
|
1435
|
+
ssn: { pattern: '\\b\\d{3}-\\d{2}-\\d{4}\\b', replacement: '[SSN]' },
|
|
1436
|
+
creditCard: { pattern: '\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b', replacement: '[CC]' },
|
|
1437
|
+
},
|
|
1438
|
+
},
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
// Synchronous PII scrubber for log objects (defense in depth)
|
|
1443
|
+
export function scrubLogObject(obj: Record<string, unknown>): Record<string, unknown> {
|
|
1444
|
+
const SENSITIVE_KEYS = new Set([
|
|
1445
|
+
'password', 'passwd', 'pwd', 'secret', 'token', 'apikey',
|
|
1446
|
+
'api_key', 'authorization', 'auth', 'cookie', 'session',
|
|
1447
|
+
'ssn', 'social_security', 'credit_card', 'creditcard', 'cvv',
|
|
1448
|
+
'card_number', 'private_key', 'privatekey',
|
|
1449
|
+
]);
|
|
1450
|
+
|
|
1451
|
+
const scrubbed: Record<string, unknown> = {};
|
|
1452
|
+
|
|
1453
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1454
|
+
const lowerKey = key.toLowerCase();
|
|
1455
|
+
|
|
1456
|
+
if (SENSITIVE_KEYS.has(lowerKey)) {
|
|
1457
|
+
scrubbed[key] = '[REDACTED]';
|
|
1458
|
+
} else if (typeof value === 'string') {
|
|
1459
|
+
scrubbed[key] = redactPIIFromString(value);
|
|
1460
|
+
} else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
1461
|
+
scrubbed[key] = scrubLogObject(value as Record<string, unknown>);
|
|
1462
|
+
} else {
|
|
1463
|
+
scrubbed[key] = value;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
return scrubbed;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
function redactPIIFromString(value: string): string {
|
|
1471
|
+
return value
|
|
1472
|
+
.replace(/[\w.-]+@[\w.-]+\.\w+/g, '[EMAIL]')
|
|
1473
|
+
.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN]')
|
|
1474
|
+
.replace(/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g, '[CC]')
|
|
1475
|
+
.replace(/eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '[JWT]');
|
|
1476
|
+
}
|
|
1477
|
+
```
|
|
1478
|
+
|
|
1479
|
+
### 10.4 CloudTrail Analysis — Detect Suspicious AWS Activity
|
|
1480
|
+
|
|
1481
|
+
```python
|
|
1482
|
+
"""
|
|
1483
|
+
Analyze CloudTrail logs for suspicious AWS activity patterns.
|
|
1484
|
+
Intended for Lambda function triggered by CloudWatch Events.
|
|
1485
|
+
"""
|
|
1486
|
+
import json
|
|
1487
|
+
import boto3
|
|
1488
|
+
from datetime import datetime, timezone
|
|
1489
|
+
|
|
1490
|
+
sns_client = boto3.client('sns')
|
|
1491
|
+
ALERT_TOPIC_ARN = 'arn:aws:sns:us-east-1:123456789:security-alerts'
|
|
1492
|
+
|
|
1493
|
+
# High-risk events that should always trigger alerts
|
|
1494
|
+
CRITICAL_EVENTS = {
|
|
1495
|
+
'ConsoleLogin', # Root or unusual console login
|
|
1496
|
+
'StopLogging', # CloudTrail disabled — evasion
|
|
1497
|
+
'DeleteTrail', # CloudTrail deleted — evasion
|
|
1498
|
+
'PutBucketPolicy', # S3 bucket policy change
|
|
1499
|
+
'AuthorizeSecurityGroupIngress', # Security group opened
|
|
1500
|
+
'CreateAccessKey', # New access key — persistence
|
|
1501
|
+
'AttachUserPolicy', # IAM policy change — escalation
|
|
1502
|
+
'AttachRolePolicy', # IAM role change — escalation
|
|
1503
|
+
'PutRolePolicy', # Inline policy — escalation
|
|
1504
|
+
'CreateUser', # New IAM user — persistence
|
|
1505
|
+
'DeleteFlowLogs', # VPC flow logs deleted — evasion
|
|
1506
|
+
'DisableKey', # KMS key disabled — impact
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
# Events indicating potential reconnaissance
|
|
1510
|
+
RECON_EVENTS = {
|
|
1511
|
+
'DescribeInstances', 'ListBuckets', 'GetBucketAcl',
|
|
1512
|
+
'ListUsers', 'ListRoles', 'ListAccessKeys',
|
|
1513
|
+
'DescribeSecurityGroups', 'GetCallerIdentity',
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
|
|
1517
|
+
def handler(event: dict, context) -> dict:
|
|
1518
|
+
"""Process CloudTrail event from CloudWatch Events."""
|
|
1519
|
+
detail = event.get('detail', {})
|
|
1520
|
+
event_name = detail.get('eventName', '')
|
|
1521
|
+
user_identity = detail.get('userIdentity', {})
|
|
1522
|
+
source_ip = detail.get('sourceIPAddress', '')
|
|
1523
|
+
user_agent = detail.get('userAgent', '')
|
|
1524
|
+
event_time = detail.get('eventTime', '')
|
|
1525
|
+
|
|
1526
|
+
# CRITICAL: CloudTrail logging being disabled
|
|
1527
|
+
if event_name in ('StopLogging', 'DeleteTrail', 'DeleteFlowLogs'):
|
|
1528
|
+
alert(
|
|
1529
|
+
severity='CRITICAL',
|
|
1530
|
+
title=f'Logging evasion detected: {event_name}',
|
|
1531
|
+
detail=detail,
|
|
1532
|
+
)
|
|
1533
|
+
return {'action': 'alert_sent', 'severity': 'critical'}
|
|
1534
|
+
|
|
1535
|
+
# Root account usage (should be extremely rare)
|
|
1536
|
+
if user_identity.get('type') == 'Root':
|
|
1537
|
+
alert(
|
|
1538
|
+
severity='CRITICAL',
|
|
1539
|
+
title=f'Root account used: {event_name}',
|
|
1540
|
+
detail=detail,
|
|
1541
|
+
)
|
|
1542
|
+
return {'action': 'alert_sent', 'severity': 'critical'}
|
|
1543
|
+
|
|
1544
|
+
# High-risk IAM changes
|
|
1545
|
+
if event_name in CRITICAL_EVENTS:
|
|
1546
|
+
alert(
|
|
1547
|
+
severity='HIGH',
|
|
1548
|
+
title=f'Critical security event: {event_name}',
|
|
1549
|
+
detail=detail,
|
|
1550
|
+
)
|
|
1551
|
+
|
|
1552
|
+
# Detect reconnaissance bursts
|
|
1553
|
+
if event_name in RECON_EVENTS:
|
|
1554
|
+
# In production, check against a sliding window counter
|
|
1555
|
+
# (e.g., DynamoDB or ElastiCache) for burst detection
|
|
1556
|
+
pass
|
|
1557
|
+
|
|
1558
|
+
# Detect access from unusual source IPs
|
|
1559
|
+
if source_ip and not is_known_ip(source_ip):
|
|
1560
|
+
alert(
|
|
1561
|
+
severity='MEDIUM',
|
|
1562
|
+
title=f'Activity from unknown IP: {source_ip}',
|
|
1563
|
+
detail=detail,
|
|
1564
|
+
)
|
|
1565
|
+
|
|
1566
|
+
return {'action': 'processed'}
|
|
1567
|
+
|
|
1568
|
+
|
|
1569
|
+
def alert(severity: str, title: str, detail: dict) -> None:
|
|
1570
|
+
"""Send security alert via SNS."""
|
|
1571
|
+
message = {
|
|
1572
|
+
'severity': severity,
|
|
1573
|
+
'title': title,
|
|
1574
|
+
'timestamp': datetime.now(timezone.utc).isoformat(),
|
|
1575
|
+
'event_name': detail.get('eventName'),
|
|
1576
|
+
'user': detail.get('userIdentity', {}).get('arn', 'unknown'),
|
|
1577
|
+
'source_ip': detail.get('sourceIPAddress'),
|
|
1578
|
+
'region': detail.get('awsRegion'),
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
sns_client.publish(
|
|
1582
|
+
TopicArn=ALERT_TOPIC_ARN,
|
|
1583
|
+
Subject=f'[{severity}] {title}',
|
|
1584
|
+
Message=json.dumps(message, indent=2),
|
|
1585
|
+
)
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
def is_known_ip(ip: str) -> bool:
|
|
1589
|
+
"""Check if IP is in the known corporate/VPN CIDR ranges."""
|
|
1590
|
+
# In production: check against a maintained allowlist
|
|
1591
|
+
# stored in Parameter Store or DynamoDB
|
|
1592
|
+
return False # Default deny — alert on all unknown IPs
|
|
1593
|
+
```
|
|
1594
|
+
|
|
1595
|
+
---
|
|
1596
|
+
|
|
1597
|
+
## References
|
|
1598
|
+
|
|
1599
|
+
- [OWASP Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html)
|
|
1600
|
+
- [OWASP Logging Vocabulary Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html)
|
|
1601
|
+
- [OWASP A09:2021 — Security Logging and Monitoring Failures](https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/)
|
|
1602
|
+
- [NIST SP 800-92 — Guide to Computer Security Log Management](https://csrc.nist.gov/pubs/sp/800/92/final)
|
|
1603
|
+
- [NIST SP 800-92 Rev. 1 (Draft) — Cybersecurity Log Management Planning Guide](https://csrc.nist.gov/pubs/sp/800/92/r1/ipd)
|
|
1604
|
+
- [IBM Cost of a Data Breach Report 2024](https://newsroom.ibm.com/2024-07-30-ibm-report-escalating-data-breach-disruption-pushes-costs-to-new-highs)
|
|
1605
|
+
- [MITRE ATT&CK — Indicator Removal T1070](https://attack.mitre.org/techniques/T1070/)
|
|
1606
|
+
- [MITRE ATT&CK — Impair Defenses T1562](https://attack.mitre.org/techniques/T1562/)
|
|
1607
|
+
- [CWE-117: Improper Output Neutralization for Logs](https://cwe.mitre.org/data/definitions/117.html)
|
|
1608
|
+
- [CWE-778: Insufficient Logging](https://cwe.mitre.org/cgi-bin/index.cgi)
|
|
1609
|
+
- [CWE-532: Insertion of Sensitive Information into Log File](https://cwe.mitre.org/cgi-bin/index.cgi)
|
|
1610
|
+
- [PCI DSS v4.0 Requirement 10](https://pcidssguide.com/pci-dss-logging-requirements/)
|
|
1611
|
+
- [2017 Equifax Data Breach — Wikipedia](https://en.wikipedia.org/wiki/2017_Equifax_data_breach)
|
|
1612
|
+
- [SolarWinds Attack — Aqua Security](https://www.aquasec.com/cloud-native-academy/supply-chain-security/solarwinds-attack/)
|
|
1613
|
+
- [Log4Shell — CISA Guidance](https://www.cisa.gov/news-events/news/apache-log4j-vulnerability-guidance)
|
|
1614
|
+
- [AWS CloudTrail Security Best Practices](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/best-practices-security.html)
|
|
1615
|
+
- [Amazon GuardDuty Best Practices](https://aws.github.io/aws-security-services-best-practices/guides/guardduty/)
|
|
1616
|
+
- [Falco — CNCF Runtime Security](https://www.sysdig.com/opensource/falco)
|
|
1617
|
+
- [Wazuh — Cloud Native Security](https://wazuh.com/blog/cloud-native-security-with-wazuh-and-falco/)
|
|
1618
|
+
- [Thinkst Canary](https://canary.tools/)
|