@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,1218 @@
|
|
|
1
|
+
# Mobile Android Security
|
|
2
|
+
|
|
3
|
+
> Expertise module for AI agents building secure Android applications.
|
|
4
|
+
> Covers threat landscape, implementation patterns, vulnerability catalog, and compliance.
|
|
5
|
+
> Last updated: 2026-03-08 | Sources: OWASP MASVS v2.1, OWASP Mobile Top 10 2024, Android Security Bulletins, NowSecure, Google Android Developer Docs.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Threat Landscape
|
|
10
|
+
|
|
11
|
+
### 1.1 Android-Specific Attack Surface
|
|
12
|
+
|
|
13
|
+
Android's open ecosystem creates a broader attack surface than closed platforms:
|
|
14
|
+
|
|
15
|
+
- **APK Reverse Engineering** -- Android apps compile to Dalvik bytecode (DEX), which is significantly easier to decompile than native ARM binaries. Tools like jadx, APKTool, and dex2jar can reconstruct near-source-quality Java/Kotlin code in seconds. Attackers extract API keys, authentication logic, encryption routines, and server endpoints from decompiled APKs.
|
|
16
|
+
|
|
17
|
+
- **Rooting** -- Rooting grants superuser access, bypassing the Android sandbox. Rooted devices allow attackers to: read any app's private data directory (`/data/data/<package>`), hook method calls at runtime via Frida, bypass SSL pinning and root detection, extract keys from the app's memory.
|
|
18
|
+
|
|
19
|
+
- **Component Exposure** -- Android's inter-process communication (IPC) model exposes Activities, Services, BroadcastReceivers, and ContentProviders. Exported components (explicit `android:exported="true"` or implicit via intent-filters) are accessible to any app on the device. Attackers craft malicious intents to invoke unprotected components.
|
|
20
|
+
|
|
21
|
+
- **Intent Injection** -- Malicious apps send crafted intents to vulnerable components, triggering unauthorized actions. Implicit intents can be intercepted by attacker-installed apps that register matching intent-filters. Pending intents with mutable flags can be modified by receiving apps.
|
|
22
|
+
|
|
23
|
+
- **WebView Attacks** -- WebViews that enable JavaScript and use `addJavascriptInterface()` expose native Java methods to web content. Attackers inject scripts via XSS or man-in-the-middle attacks to call native methods with the host app's permissions. `postWebMessage()` without origin validation allows cross-origin message injection.
|
|
24
|
+
|
|
25
|
+
- **Sideloading Malware** -- Android permits APK installation from unknown sources. Malicious apps masquerade as legitimate tools, banking apps, or games. Google Play Protect catches some threats, but sideloaded apps bypass store-level scanning entirely.
|
|
26
|
+
|
|
27
|
+
- **Clipboard Data Exposure** -- Prior to Android 13, any app could silently read clipboard contents. Sensitive data (passwords, OTPs, account numbers) copied to clipboard was accessible to all running apps.
|
|
28
|
+
|
|
29
|
+
### 1.2 Real-World Incidents
|
|
30
|
+
|
|
31
|
+
**SharkBot Banking Trojan (2021-2024)**
|
|
32
|
+
SharkBot initiates money transfers from compromised devices using Automatic Transfer Systems (ATS). It abuses Android Accessibility Services to overlay fake login screens, intercept SMS-based 2FA codes, and perform actions without user awareness. Distributed through Google Play Store as "file manager" and "antivirus" apps that passed initial review then downloaded the payload post-install. Targeted banking apps across Europe and the US. (Source: Cleafy Labs, NCC Group)
|
|
33
|
+
|
|
34
|
+
**Vultur Banking Trojan (2021-2025)**
|
|
35
|
+
Vultur uses VNC-based screen recording and remote control via Android Accessibility Services. The 2024 variant added encrypted C2 communication, file management capabilities (download/upload/delete/install), and improved anti-analysis with native code obfuscation. Distributed via smishing campaigns that direct victims to sideload a trojanized app. (Source: ThreatFabric, The Hacker News)
|
|
36
|
+
|
|
37
|
+
**Pegasus Spyware (2016-present)**
|
|
38
|
+
Developed by NSO Group, Pegasus exploits zero-click vulnerabilities to install itself without user interaction on both iOS and Android. Capabilities include microphone/camera control, message extraction, location tracking, and keylogging. In 2024, iVerify researchers found 2.5 infected devices per 1,000 scans -- significantly higher than previously estimated. In May 2025, NSO Group was ordered to pay $167 million in damages to WhatsApp. (Source: iVerify, Citizen Lab)
|
|
39
|
+
|
|
40
|
+
**Predator Spyware (2022-2024)**
|
|
41
|
+
Developed by Cytrox/Intellexa, Predator targets Android and iOS using exploit chains delivered via one-click links. Capabilities mirror Pegasus. The EU Parliament investigated its use against European politicians and journalists. (Source: Google TAG, Lookout)
|
|
42
|
+
|
|
43
|
+
**Joker/Bread Malware Family**
|
|
44
|
+
Persistent malware family that subscribes users to premium services via WAP billing fraud. Continually evolves to bypass Play Store defenses, with over 1,700 infected apps removed since 2017. Uses a combination of obfuscation, code loading, and delayed payload execution. (Source: Google, Kaspersky)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 2. Core Security Principles
|
|
49
|
+
|
|
50
|
+
### 2.1 Android Security Model
|
|
51
|
+
|
|
52
|
+
**Application Sandbox** -- Each app runs in its own Linux process with a unique UID. Apps cannot access each other's files unless explicitly shared via ContentProviders or file-sharing mechanisms. SELinux enforces mandatory access control policies on all processes.
|
|
53
|
+
|
|
54
|
+
**Permission Model** -- Runtime permissions (dangerous permissions) require explicit user consent at runtime. Android 14+ requires apps to declare exact foreground service types and request corresponding permissions. Android 15 introduced temporary permission settings for camera/microphone that auto-expire.
|
|
55
|
+
|
|
56
|
+
**Android Keystore System** -- Hardware-backed (TEE/SE) cryptographic key storage. Key material never enters the application process -- crypto operations are performed in the secure environment. Keys can be bound to user authentication (biometric/PIN), requiring re-authentication before use.
|
|
57
|
+
|
|
58
|
+
### 2.2 Component Security
|
|
59
|
+
|
|
60
|
+
Every component must explicitly declare its export status (mandatory since Android 12/targetSdk 31):
|
|
61
|
+
|
|
62
|
+
```xml
|
|
63
|
+
<!-- SECURE: Explicitly not exported -->
|
|
64
|
+
<activity
|
|
65
|
+
android:name=".InternalActivity"
|
|
66
|
+
android:exported="false" />
|
|
67
|
+
|
|
68
|
+
<!-- SECURE: Exported with permission guard -->
|
|
69
|
+
<service
|
|
70
|
+
android:name=".DataSyncService"
|
|
71
|
+
android:exported="true"
|
|
72
|
+
android:permission="com.example.SYNC_PERMISSION" />
|
|
73
|
+
|
|
74
|
+
<!-- INSECURE: Exported without protection -->
|
|
75
|
+
<receiver
|
|
76
|
+
android:name=".AdminReceiver"
|
|
77
|
+
android:exported="true" />
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Intent Filter Security** -- Components with intent-filters are implicitly exported (pre-Android 12). Always set `android:exported="false"` explicitly for internal components. Use custom permissions with `signature` protection level for inter-app communication between your own apps.
|
|
81
|
+
|
|
82
|
+
### 2.3 Data Storage Security
|
|
83
|
+
|
|
84
|
+
| Storage Type | Security Level | When to Use |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| Internal storage (`/data/data/<pkg>`) | App-sandbox protected | Non-sensitive app data |
|
|
87
|
+
| EncryptedSharedPreferences / Keystore+SharedPrefs | AES-256-GCM encrypted | Tokens, user preferences with sensitive values |
|
|
88
|
+
| Android Keystore | Hardware-backed | Cryptographic keys, biometric-bound secrets |
|
|
89
|
+
| External storage | World-readable | Never for sensitive data |
|
|
90
|
+
| SQLCipher / Room + encryption | AES-256 | Encrypted local databases |
|
|
91
|
+
|
|
92
|
+
### 2.4 Network Security Configuration
|
|
93
|
+
|
|
94
|
+
Android's `network_security_config.xml` controls network behavior declaratively:
|
|
95
|
+
|
|
96
|
+
```xml
|
|
97
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
98
|
+
<network-security-config>
|
|
99
|
+
<!-- Block all cleartext (HTTP) traffic -->
|
|
100
|
+
<base-config cleartextTrafficPermitted="false">
|
|
101
|
+
<trust-anchors>
|
|
102
|
+
<certificates src="system" />
|
|
103
|
+
</trust-anchors>
|
|
104
|
+
</base-config>
|
|
105
|
+
|
|
106
|
+
<!-- Certificate pinning for API domain -->
|
|
107
|
+
<domain-config>
|
|
108
|
+
<domain includeSubdomains="true">api.example.com</domain>
|
|
109
|
+
<pin-set expiration="2026-06-01">
|
|
110
|
+
<pin digest="SHA-256">base64EncodedSPKIHash=</pin>
|
|
111
|
+
<!-- Backup pin (REQUIRED -- use a different CA) -->
|
|
112
|
+
<pin digest="SHA-256">backupBase64EncodedSPKIHash=</pin>
|
|
113
|
+
</pin-set>
|
|
114
|
+
</domain-config>
|
|
115
|
+
|
|
116
|
+
<!-- Debug-only: trust user-installed CAs for testing -->
|
|
117
|
+
<debug-overrides>
|
|
118
|
+
<trust-anchors>
|
|
119
|
+
<certificates src="user" />
|
|
120
|
+
</trust-anchors>
|
|
121
|
+
</debug-overrides>
|
|
122
|
+
</network-security-config>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 2.5 Code Obfuscation (R8/ProGuard)
|
|
126
|
+
|
|
127
|
+
R8 (the default Android code shrinker since AGP 3.4) performs:
|
|
128
|
+
- **Code shrinking** -- removes unused classes, methods, fields
|
|
129
|
+
- **Obfuscation** -- renames classes/methods to short meaningless names
|
|
130
|
+
- **Optimization** -- inlines methods, removes dead branches
|
|
131
|
+
|
|
132
|
+
```groovy
|
|
133
|
+
// build.gradle.kts
|
|
134
|
+
android {
|
|
135
|
+
buildTypes {
|
|
136
|
+
release {
|
|
137
|
+
isMinifyEnabled = true
|
|
138
|
+
isShrinkResources = true
|
|
139
|
+
proguardFiles(
|
|
140
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
141
|
+
"proguard-rules.pro"
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
R8 makes reverse engineering harder but is NOT a security boundary. Determined attackers can still analyze the bytecode. Combine with additional protections (integrity checks, server-side validation).
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 3. Implementation Patterns
|
|
153
|
+
|
|
154
|
+
### 3.1 Android Keystore -- Key Generation and Usage
|
|
155
|
+
|
|
156
|
+
```kotlin
|
|
157
|
+
import android.security.keystore.KeyGenParameterSpec
|
|
158
|
+
import android.security.keystore.KeyProperties
|
|
159
|
+
import java.security.KeyStore
|
|
160
|
+
import javax.crypto.Cipher
|
|
161
|
+
import javax.crypto.KeyGenerator
|
|
162
|
+
import javax.crypto.SecretKey
|
|
163
|
+
import javax.crypto.spec.GCMParameterSpec
|
|
164
|
+
|
|
165
|
+
object KeystoreManager {
|
|
166
|
+
|
|
167
|
+
private const val KEYSTORE_PROVIDER = "AndroidKeyStore"
|
|
168
|
+
private const val KEY_ALIAS = "app_secret_key"
|
|
169
|
+
private const val AES_GCM_NOPADDING = "AES/GCM/NoPadding"
|
|
170
|
+
private const val GCM_TAG_LENGTH = 128
|
|
171
|
+
|
|
172
|
+
fun generateKey(): SecretKey {
|
|
173
|
+
val keyGenerator = KeyGenerator.getInstance(
|
|
174
|
+
KeyProperties.KEY_ALGORITHM_AES,
|
|
175
|
+
KEYSTORE_PROVIDER
|
|
176
|
+
)
|
|
177
|
+
val spec = KeyGenParameterSpec.Builder(
|
|
178
|
+
KEY_ALIAS,
|
|
179
|
+
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
|
180
|
+
)
|
|
181
|
+
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
|
182
|
+
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
|
183
|
+
.setKeySize(256)
|
|
184
|
+
.setUserAuthenticationRequired(true)
|
|
185
|
+
.setUserAuthenticationParameters(
|
|
186
|
+
300, KeyProperties.AUTH_BIOMETRIC_STRONG
|
|
187
|
+
)
|
|
188
|
+
.setInvalidatedByBiometricEnrollment(true)
|
|
189
|
+
.setIsStrongBoxBacked(false) // Set true if StrongBox available
|
|
190
|
+
.build()
|
|
191
|
+
keyGenerator.init(spec)
|
|
192
|
+
return keyGenerator.generateKey()
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
fun getKey(): SecretKey? {
|
|
196
|
+
val keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER)
|
|
197
|
+
.apply { load(null) }
|
|
198
|
+
return keyStore.getKey(KEY_ALIAS, null) as? SecretKey
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
fun encrypt(plaintext: ByteArray): Pair<ByteArray, ByteArray> {
|
|
202
|
+
val key = getKey() ?: generateKey()
|
|
203
|
+
val cipher = Cipher.getInstance(AES_GCM_NOPADDING)
|
|
204
|
+
cipher.init(Cipher.ENCRYPT_MODE, key)
|
|
205
|
+
val iv = cipher.iv
|
|
206
|
+
val ciphertext = cipher.doFinal(plaintext)
|
|
207
|
+
return Pair(iv, ciphertext)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
fun decrypt(iv: ByteArray, ciphertext: ByteArray): ByteArray {
|
|
211
|
+
val key = getKey()
|
|
212
|
+
?: throw IllegalStateException("Key not found")
|
|
213
|
+
val cipher = Cipher.getInstance(AES_GCM_NOPADDING)
|
|
214
|
+
val spec = GCMParameterSpec(GCM_TAG_LENGTH, iv)
|
|
215
|
+
cipher.init(Cipher.DECRYPT_MODE, key, spec)
|
|
216
|
+
return cipher.doFinal(ciphertext)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 3.2 EncryptedSharedPreferences (Secure Token Storage)
|
|
222
|
+
|
|
223
|
+
> Note: `androidx.security:security-crypto` was deprecated in April 2025.
|
|
224
|
+
> Google recommends direct Android Keystore usage. Community forks
|
|
225
|
+
> (e.g., ed-george/encrypted-shared-preferences) continue maintenance.
|
|
226
|
+
> The pattern below remains valid for existing codebases or via the fork.
|
|
227
|
+
|
|
228
|
+
```kotlin
|
|
229
|
+
import androidx.security.crypto.EncryptedSharedPreferences
|
|
230
|
+
import androidx.security.crypto.MasterKeys
|
|
231
|
+
|
|
232
|
+
// SECURE: Encrypted storage for sensitive values
|
|
233
|
+
fun getSecurePrefs(context: Context): SharedPreferences {
|
|
234
|
+
val masterKeyAlias = MasterKeys.getOrCreate(
|
|
235
|
+
MasterKeys.AES256_GCM_SPEC
|
|
236
|
+
)
|
|
237
|
+
return EncryptedSharedPreferences.create(
|
|
238
|
+
"secure_prefs",
|
|
239
|
+
masterKeyAlias,
|
|
240
|
+
context,
|
|
241
|
+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
|
242
|
+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Usage
|
|
247
|
+
val prefs = getSecurePrefs(context)
|
|
248
|
+
prefs.edit().putString("auth_token", token).apply()
|
|
249
|
+
val storedToken = prefs.getString("auth_token", null)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Post-deprecation alternative using Keystore + Tink directly:**
|
|
253
|
+
|
|
254
|
+
```kotlin
|
|
255
|
+
import com.google.crypto.tink.Aead
|
|
256
|
+
import com.google.crypto.tink.KeysetHandle
|
|
257
|
+
import com.google.crypto.tink.aead.AeadConfig
|
|
258
|
+
import com.google.crypto.tink.integration.android.AndroidKeysetManager
|
|
259
|
+
|
|
260
|
+
object SecureStorage {
|
|
261
|
+
private const val KEYSET_NAME = "app_keyset"
|
|
262
|
+
private const val PREF_FILE = "app_keyset_prefs"
|
|
263
|
+
private const val MASTER_KEY_URI = "android-keystore://master_key"
|
|
264
|
+
|
|
265
|
+
fun getAead(context: Context): Aead {
|
|
266
|
+
AeadConfig.register()
|
|
267
|
+
val keysetHandle: KeysetHandle = AndroidKeysetManager.Builder()
|
|
268
|
+
.withSharedPref(context, KEYSET_NAME, PREF_FILE)
|
|
269
|
+
.withKeyTemplate(
|
|
270
|
+
com.google.crypto.tink.aead.AeadKeyTemplates.AES256_GCM
|
|
271
|
+
)
|
|
272
|
+
.withMasterKeyUri(MASTER_KEY_URI)
|
|
273
|
+
.build()
|
|
274
|
+
.keysetHandle
|
|
275
|
+
return keysetHandle.getPrimitive(Aead::class.java)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
fun encrypt(
|
|
279
|
+
context: Context,
|
|
280
|
+
plaintext: ByteArray,
|
|
281
|
+
aad: ByteArray = byteArrayOf()
|
|
282
|
+
): ByteArray {
|
|
283
|
+
return getAead(context).encrypt(plaintext, aad)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
fun decrypt(
|
|
287
|
+
context: Context,
|
|
288
|
+
ciphertext: ByteArray,
|
|
289
|
+
aad: ByteArray = byteArrayOf()
|
|
290
|
+
): ByteArray {
|
|
291
|
+
return getAead(context).decrypt(ciphertext, aad)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 3.3 BiometricPrompt Authentication
|
|
297
|
+
|
|
298
|
+
```kotlin
|
|
299
|
+
import androidx.biometric.BiometricManager
|
|
300
|
+
import androidx.biometric.BiometricPrompt
|
|
301
|
+
import androidx.core.content.ContextCompat
|
|
302
|
+
import androidx.fragment.app.FragmentActivity
|
|
303
|
+
|
|
304
|
+
class BiometricAuthManager(private val activity: FragmentActivity) {
|
|
305
|
+
|
|
306
|
+
fun canAuthenticate(): Boolean {
|
|
307
|
+
val biometricManager = BiometricManager.from(activity)
|
|
308
|
+
return biometricManager.canAuthenticate(
|
|
309
|
+
BiometricManager.Authenticators.BIOMETRIC_STRONG
|
|
310
|
+
) == BiometricManager.BIOMETRIC_SUCCESS
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
fun authenticate(
|
|
314
|
+
onSuccess: (BiometricPrompt.AuthenticationResult) -> Unit,
|
|
315
|
+
onError: (Int, CharSequence) -> Unit
|
|
316
|
+
) {
|
|
317
|
+
val executor = ContextCompat.getMainExecutor(activity)
|
|
318
|
+
|
|
319
|
+
val callback = object : BiometricPrompt.AuthenticationCallback() {
|
|
320
|
+
override fun onAuthenticationSucceeded(
|
|
321
|
+
result: BiometricPrompt.AuthenticationResult
|
|
322
|
+
) {
|
|
323
|
+
super.onAuthenticationSucceeded(result)
|
|
324
|
+
onSuccess(result)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
override fun onAuthenticationError(
|
|
328
|
+
errorCode: Int, errString: CharSequence
|
|
329
|
+
) {
|
|
330
|
+
super.onAuthenticationError(errorCode, errString)
|
|
331
|
+
onError(errorCode, errString)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
val biometricPrompt = BiometricPrompt(
|
|
336
|
+
activity, executor, callback
|
|
337
|
+
)
|
|
338
|
+
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
|
339
|
+
.setTitle("Authentication Required")
|
|
340
|
+
.setSubtitle("Verify your identity to continue")
|
|
341
|
+
.setAllowedAuthenticators(
|
|
342
|
+
BiometricManager.Authenticators.BIOMETRIC_STRONG
|
|
343
|
+
)
|
|
344
|
+
.setNegativeButtonText("Cancel")
|
|
345
|
+
.build()
|
|
346
|
+
|
|
347
|
+
biometricPrompt.authenticate(promptInfo)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** Authenticate with a Keystore-bound CryptoObject */
|
|
351
|
+
fun authenticateWithCrypto(
|
|
352
|
+
cipher: javax.crypto.Cipher,
|
|
353
|
+
onSuccess: (BiometricPrompt.AuthenticationResult) -> Unit,
|
|
354
|
+
onError: (Int, CharSequence) -> Unit
|
|
355
|
+
) {
|
|
356
|
+
val executor = ContextCompat.getMainExecutor(activity)
|
|
357
|
+
val callback = object : BiometricPrompt.AuthenticationCallback() {
|
|
358
|
+
override fun onAuthenticationSucceeded(
|
|
359
|
+
result: BiometricPrompt.AuthenticationResult
|
|
360
|
+
) {
|
|
361
|
+
onSuccess(result)
|
|
362
|
+
}
|
|
363
|
+
override fun onAuthenticationError(
|
|
364
|
+
errorCode: Int, errString: CharSequence
|
|
365
|
+
) {
|
|
366
|
+
onError(errorCode, errString)
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
val biometricPrompt = BiometricPrompt(
|
|
370
|
+
activity, executor, callback
|
|
371
|
+
)
|
|
372
|
+
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
|
373
|
+
.setTitle("Unlock Secure Data")
|
|
374
|
+
.setAllowedAuthenticators(
|
|
375
|
+
BiometricManager.Authenticators.BIOMETRIC_STRONG
|
|
376
|
+
)
|
|
377
|
+
.setNegativeButtonText("Cancel")
|
|
378
|
+
.build()
|
|
379
|
+
biometricPrompt.authenticate(
|
|
380
|
+
promptInfo, BiometricPrompt.CryptoObject(cipher)
|
|
381
|
+
)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### 3.4 Play Integrity API (SafetyNet Replacement)
|
|
387
|
+
|
|
388
|
+
SafetyNet was fully shut down on May 20, 2025. Play Integrity API is the mandatory replacement.
|
|
389
|
+
|
|
390
|
+
```kotlin
|
|
391
|
+
import com.google.android.play.core.integrity.IntegrityManagerFactory
|
|
392
|
+
import com.google.android.play.core.integrity.IntegrityTokenRequest
|
|
393
|
+
|
|
394
|
+
class IntegrityChecker(private val context: Context) {
|
|
395
|
+
|
|
396
|
+
fun requestIntegrityToken(
|
|
397
|
+
nonce: String,
|
|
398
|
+
onResult: (String) -> Unit,
|
|
399
|
+
onError: (Exception) -> Unit
|
|
400
|
+
) {
|
|
401
|
+
val integrityManager =
|
|
402
|
+
IntegrityManagerFactory.create(context)
|
|
403
|
+
val request = IntegrityTokenRequest.builder()
|
|
404
|
+
.setNonce(nonce) // Server-generated, one-time nonce
|
|
405
|
+
.build()
|
|
406
|
+
|
|
407
|
+
integrityManager.requestIntegrityToken(request)
|
|
408
|
+
.addOnSuccessListener { response ->
|
|
409
|
+
// Send token to YOUR server for verification
|
|
410
|
+
// NEVER verify on-device -- server-side only
|
|
411
|
+
onResult(response.token())
|
|
412
|
+
}
|
|
413
|
+
.addOnFailureListener { exception ->
|
|
414
|
+
onError(exception)
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Server-side verdict fields:
|
|
420
|
+
// - requestDetails: nonce, package name, timestamp
|
|
421
|
+
// - appIntegrity: PLAY_RECOGNIZED | UNRECOGNIZED_VERSION
|
|
422
|
+
// - deviceIntegrity: MEETS_DEVICE_INTEGRITY | MEETS_BASIC_INTEGRITY
|
|
423
|
+
// - accountDetails: LICENSED | UNLICENSED
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Key points:
|
|
427
|
+
- Always generate nonces server-side to prevent replay attacks
|
|
428
|
+
- Verify the integrity token server-side, never on-device
|
|
429
|
+
- Cache verdicts with short TTLs (minutes, not hours)
|
|
430
|
+
- Handle UNEVALUATED gracefully -- it does not mean compromised
|
|
431
|
+
|
|
432
|
+
### 3.5 Secure WebView Configuration
|
|
433
|
+
|
|
434
|
+
```kotlin
|
|
435
|
+
// INSECURE: Default WebView with dangerous settings
|
|
436
|
+
fun createInsecureWebView(context: Context): WebView {
|
|
437
|
+
return WebView(context).apply {
|
|
438
|
+
settings.javaScriptEnabled = true
|
|
439
|
+
settings.allowFileAccess = true // BAD
|
|
440
|
+
settings.allowUniversalAccessFromFileURLs = true // BAD
|
|
441
|
+
addJavascriptInterface(BridgeObject(), "bridge") // BAD
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// SECURE: Hardened WebView
|
|
446
|
+
fun createSecureWebView(context: Context): WebView {
|
|
447
|
+
return WebView(context).apply {
|
|
448
|
+
settings.apply {
|
|
449
|
+
javaScriptEnabled = true // Only if truly required
|
|
450
|
+
allowFileAccess = false
|
|
451
|
+
allowContentAccess = false
|
|
452
|
+
allowFileAccessFromFileURLs = false
|
|
453
|
+
allowUniversalAccessFromFileURLs = false
|
|
454
|
+
domStorageEnabled = false
|
|
455
|
+
databaseEnabled = false
|
|
456
|
+
setGeolocationEnabled(false)
|
|
457
|
+
mixedContentMode =
|
|
458
|
+
WebSettings.MIXED_CONTENT_NEVER_ALLOW
|
|
459
|
+
cacheMode = WebSettings.LOAD_NO_CACHE
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Restrict navigation to trusted domains
|
|
463
|
+
webViewClient = object : WebViewClient() {
|
|
464
|
+
override fun shouldOverrideUrlLoading(
|
|
465
|
+
view: WebView?,
|
|
466
|
+
request: WebResourceRequest?
|
|
467
|
+
): Boolean {
|
|
468
|
+
val host = request?.url?.host ?: return true
|
|
469
|
+
val allowedHosts = setOf(
|
|
470
|
+
"app.example.com", "cdn.example.com"
|
|
471
|
+
)
|
|
472
|
+
return host !in allowedHosts
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Expose ONLY specific methods via @JavascriptInterface
|
|
477
|
+
addJavascriptInterface(SecureBridge(), "appBridge")
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
class SecureBridge {
|
|
482
|
+
@android.webkit.JavascriptInterface
|
|
483
|
+
fun getPublicData(): String {
|
|
484
|
+
// Only non-sensitive, read-only data
|
|
485
|
+
return "{\"version\": \"1.0\"}"
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### 3.6 Content Provider Security
|
|
491
|
+
|
|
492
|
+
```kotlin
|
|
493
|
+
// INSECURE manifest declaration:
|
|
494
|
+
// <provider android:authorities="com.example.data"
|
|
495
|
+
// android:exported="true"
|
|
496
|
+
// android:grantUriPermissions="true" />
|
|
497
|
+
|
|
498
|
+
// SECURE manifest declaration:
|
|
499
|
+
// <provider
|
|
500
|
+
// android:authorities="com.example.data"
|
|
501
|
+
// android:exported="true"
|
|
502
|
+
// android:readPermission="com.example.READ_DATA"
|
|
503
|
+
// android:writePermission="com.example.WRITE_DATA"
|
|
504
|
+
// android:grantUriPermissions="false" />
|
|
505
|
+
//
|
|
506
|
+
// <permission
|
|
507
|
+
// android:name="com.example.READ_DATA"
|
|
508
|
+
// android:protectionLevel="signature" />
|
|
509
|
+
|
|
510
|
+
class SecureProvider : ContentProvider() {
|
|
511
|
+
override fun query(
|
|
512
|
+
uri: Uri, projection: Array<String>?,
|
|
513
|
+
selection: String?, selectionArgs: Array<String>?,
|
|
514
|
+
sortOrder: String?
|
|
515
|
+
): Cursor? {
|
|
516
|
+
// Validate caller identity
|
|
517
|
+
val callingPackage = callingPackage
|
|
518
|
+
?: throw SecurityException("Unknown caller")
|
|
519
|
+
|
|
520
|
+
// Prevent path traversal
|
|
521
|
+
val pathSegments = uri.pathSegments
|
|
522
|
+
if (pathSegments.any { it.contains("..") }) {
|
|
523
|
+
throw SecurityException("Path traversal detected")
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Use parameterized queries only
|
|
527
|
+
return database.query(
|
|
528
|
+
getTableName(uri), projection,
|
|
529
|
+
selection, selectionArgs, sortOrder
|
|
530
|
+
)
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### 3.7 Root Detection
|
|
536
|
+
|
|
537
|
+
```kotlin
|
|
538
|
+
object RootDetector {
|
|
539
|
+
|
|
540
|
+
fun isDeviceRooted(): Boolean {
|
|
541
|
+
return checkSuBinary() ||
|
|
542
|
+
checkRootManagementApps() ||
|
|
543
|
+
checkDangerousProps() ||
|
|
544
|
+
checkRWPaths() ||
|
|
545
|
+
checkTestKeys()
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
private fun checkSuBinary(): Boolean {
|
|
549
|
+
val paths = arrayOf(
|
|
550
|
+
"/system/bin/su", "/system/xbin/su",
|
|
551
|
+
"/sbin/su", "/data/local/xbin/su",
|
|
552
|
+
"/data/local/bin/su", "/system/sd/xbin/su",
|
|
553
|
+
"/system/bin/failsafe/su", "/data/local/su",
|
|
554
|
+
"/su/bin/su"
|
|
555
|
+
)
|
|
556
|
+
return paths.any { java.io.File(it).exists() }
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
private fun checkRootManagementApps(): Boolean {
|
|
560
|
+
val packages = arrayOf(
|
|
561
|
+
"com.topjohnwu.magisk",
|
|
562
|
+
"eu.chainfire.supersu",
|
|
563
|
+
"com.koushikdutta.superuser",
|
|
564
|
+
"com.thirdparty.superuser",
|
|
565
|
+
"com.noshufou.android.su"
|
|
566
|
+
)
|
|
567
|
+
// Check via packageManager.getPackageInfo()
|
|
568
|
+
return false
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
private fun checkDangerousProps(): Boolean {
|
|
572
|
+
return try {
|
|
573
|
+
val process = Runtime.getRuntime()
|
|
574
|
+
.exec(arrayOf("getprop", "ro.debuggable"))
|
|
575
|
+
val result = process.inputStream
|
|
576
|
+
.bufferedReader().readLine()
|
|
577
|
+
result == "1"
|
|
578
|
+
} catch (e: Exception) { false }
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
private fun checkRWPaths(): Boolean {
|
|
582
|
+
return try {
|
|
583
|
+
val process = Runtime.getRuntime()
|
|
584
|
+
.exec(arrayOf("mount"))
|
|
585
|
+
val output = process.inputStream
|
|
586
|
+
.bufferedReader().readText()
|
|
587
|
+
output.contains("/system") && output.contains("rw,")
|
|
588
|
+
} catch (e: Exception) { false }
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
private fun checkTestKeys(): Boolean {
|
|
592
|
+
val buildTags = android.os.Build.TAGS
|
|
593
|
+
return buildTags != null && buildTags.contains("test-keys")
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**Important caveat:** Client-side root detection can always be bypassed by a determined attacker using Frida or similar instrumentation tools. Root detection is a speed bump, not a security boundary. Critical security decisions must be validated server-side using Play Integrity API verdicts.
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## 4. Vulnerability Catalog
|
|
603
|
+
|
|
604
|
+
### V-AND-01: Plaintext Data in SharedPreferences
|
|
605
|
+
- **Risk:** HIGH | **OWASP:** M9 (Insecure Data Storage) | **MASVS:** MASVS-STORAGE
|
|
606
|
+
- **Description:** Standard `SharedPreferences` stores data as plaintext XML in `/data/data/<pkg>/shared_prefs/`. On rooted devices or via backup extraction, all stored tokens, passwords, and PII are exposed.
|
|
607
|
+
- **Fix:** Use EncryptedSharedPreferences (or Keystore + Tink) for sensitive values. Never store passwords or long-lived tokens in plaintext SharedPreferences.
|
|
608
|
+
|
|
609
|
+
### V-AND-02: Exported Components Without Permission Guards
|
|
610
|
+
- **Risk:** HIGH | **OWASP:** M8 (Security Misconfiguration) | **MASVS:** MASVS-PLATFORM
|
|
611
|
+
- **Description:** Activities, Services, BroadcastReceivers, or ContentProviders with `android:exported="true"` and no `android:permission` attribute are accessible to any app on the device. Attackers can trigger privileged actions, extract data, or inject malicious input.
|
|
612
|
+
- **Fix:** Set `android:exported="false"` for internal components. For exported components, require custom `signature`-level permissions.
|
|
613
|
+
|
|
614
|
+
### V-AND-03: Intent Sniffing and Injection
|
|
615
|
+
- **Risk:** MEDIUM-HIGH | **OWASP:** M8 (Security Misconfiguration) | **MASVS:** MASVS-PLATFORM
|
|
616
|
+
- **Description:** Implicit intents can be intercepted by any app that registers a matching intent-filter. Sensitive data passed via intent extras (user IDs, tokens, file URIs) is exposed. Mutable PendingIntents (`FLAG_MUTABLE`) can be modified by the receiving app.
|
|
617
|
+
- **Fix:** Use explicit intents for internal communication. Use `FLAG_IMMUTABLE` for PendingIntents (required for targetSdk 31+). Validate all incoming intent data.
|
|
618
|
+
|
|
619
|
+
### V-AND-04: WebView JavaScript Bridge Exploitation
|
|
620
|
+
- **Risk:** HIGH | **OWASP:** M4 (Insufficient Input/Output Validation) | **MASVS:** MASVS-PLATFORM
|
|
621
|
+
- **Description:** `addJavascriptInterface()` injects Java objects into every frame of the WebView including iframes. Post-Android 4.2, only `@JavascriptInterface`-annotated methods are exposed, but if those methods access sensitive resources, attackers exploit them via injected scripts.
|
|
622
|
+
- **Fix:** Minimize exposed bridge methods. Never expose methods that modify state or return sensitive data. Validate WebView URL origins. Prefer `postWebMessage()` with strict origin matching.
|
|
623
|
+
|
|
624
|
+
### V-AND-05: Backup Data Exposure (allowBackup)
|
|
625
|
+
- **Risk:** MEDIUM | **OWASP:** M9 (Insecure Data Storage) | **MASVS:** MASVS-STORAGE
|
|
626
|
+
- **Description:** `android:allowBackup="true"` (the default) enables `adb backup` to extract the app's entire private data directory. An attacker with physical or ADB access can extract all local data.
|
|
627
|
+
- **Fix:** Set `android:allowBackup="false"` or use `fullBackupContent` to exclude sensitive files.
|
|
628
|
+
|
|
629
|
+
```xml
|
|
630
|
+
<application
|
|
631
|
+
android:allowBackup="true"
|
|
632
|
+
android:fullBackupContent="@xml/backup_rules">
|
|
633
|
+
</application>
|
|
634
|
+
|
|
635
|
+
<!-- res/xml/backup_rules.xml -->
|
|
636
|
+
<full-backup-content>
|
|
637
|
+
<exclude domain="sharedpref" path="secure_prefs.xml" />
|
|
638
|
+
<exclude domain="database" path="credentials.db" />
|
|
639
|
+
<exclude domain="file" path="auth/" />
|
|
640
|
+
</full-backup-content>
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### V-AND-06: Debug Mode in Production
|
|
644
|
+
- **Risk:** HIGH | **OWASP:** M8 (Security Misconfiguration) | **MASVS:** MASVS-CODE
|
|
645
|
+
- **Description:** `android:debuggable="true"` in a release build enables JDWP debugger attachment, `run-as` data access, and verbose logging. R8/ProGuard may not fully strip debug symbols.
|
|
646
|
+
- **Fix:** Never manually set `android:debuggable`. Let the build system set it automatically. Add CI checks to verify debuggable is false in release APKs.
|
|
647
|
+
|
|
648
|
+
### V-AND-07: Hardcoded API Keys and Secrets in APK
|
|
649
|
+
- **Risk:** HIGH | **OWASP:** M1 (Improper Credential Usage) | **MASVS:** MASVS-STORAGE
|
|
650
|
+
- **Description:** API keys, client secrets, or credentials embedded in source code, `strings.xml`, or `BuildConfig` are trivially extracted by decompiling the APK with jadx or APKTool.
|
|
651
|
+
- **Fix:** Store secrets server-side. For keys that must exist on-device (e.g., Maps API key), use API key restrictions. Use NDK for obfuscated key storage (speed bump only).
|
|
652
|
+
|
|
653
|
+
### V-AND-08: Clipboard Data Exposure
|
|
654
|
+
- **Risk:** MEDIUM | **OWASP:** M9 (Insecure Data Storage) | **MASVS:** MASVS-STORAGE
|
|
655
|
+
- **Description:** Pre-Android 13, any app could read clipboard contents silently. Users who copy passwords or OTPs expose them to all running apps.
|
|
656
|
+
- **Fix:** Disable copy on sensitive fields. Auto-clear clipboard. Use `ClipDescription.EXTRA_IS_SENSITIVE` (Android 13+).
|
|
657
|
+
|
|
658
|
+
### V-AND-09: Insecure Network Communication
|
|
659
|
+
- **Risk:** HIGH | **OWASP:** M5 (Insecure Communication) | **MASVS:** MASVS-NETWORK
|
|
660
|
+
- **Description:** Apps that permit cleartext traffic, lack certificate pinning, or trust user-installed CAs are vulnerable to man-in-the-middle attacks.
|
|
661
|
+
- **Fix:** Block cleartext traffic via network security config. Implement certificate pinning with backup pins. Do not trust user-installed CAs in production.
|
|
662
|
+
|
|
663
|
+
### V-AND-10: SQL Injection in ContentProviders
|
|
664
|
+
- **Risk:** HIGH | **OWASP:** M4 (Insufficient Input/Output Validation) | **MASVS:** MASVS-CODE
|
|
665
|
+
- **Description:** ContentProviders that concatenate user input into SQL queries are vulnerable to injection. Attackers with access to exported providers can read, modify, or delete data.
|
|
666
|
+
- **Fix:** Use parameterized queries with `selectionArgs`. Use Room DAO pattern. Validate `uri`, `projection`, and `sortOrder` parameters.
|
|
667
|
+
|
|
668
|
+
### V-AND-11: Insecure Broadcast Receivers
|
|
669
|
+
- **Risk:** MEDIUM | **OWASP:** M8 (Security Misconfiguration) | **MASVS:** MASVS-PLATFORM
|
|
670
|
+
- **Description:** Exported BroadcastReceivers that perform privileged actions without sender validation allow any app to trigger those actions. Ordered broadcasts can be intercepted.
|
|
671
|
+
- **Fix:** Use `registerReceiver()` with `RECEIVER_NOT_EXPORTED` flag (Android 14+). Require sender permissions. Validate broadcast data.
|
|
672
|
+
|
|
673
|
+
### V-AND-12: Insecure Logging
|
|
674
|
+
- **Risk:** MEDIUM | **OWASP:** M9 (Insecure Data Storage) | **MASVS:** MASVS-STORAGE
|
|
675
|
+
- **Description:** Logging sensitive data via `Log.d()` / `Log.v()` exposes it via `adb logcat`. Never log tokens, passwords, or PII.
|
|
676
|
+
- **Fix:** Strip all logging in release builds using R8 rules or Timber with a no-op tree.
|
|
677
|
+
|
|
678
|
+
```proguard
|
|
679
|
+
# proguard-rules.pro -- Strip Log calls in release
|
|
680
|
+
-assumenosideeffects class android.util.Log {
|
|
681
|
+
public static int v(...);
|
|
682
|
+
public static int d(...);
|
|
683
|
+
public static int i(...);
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### V-AND-13: Task Hijacking (StrandHogg)
|
|
688
|
+
- **Risk:** MEDIUM | **OWASP:** M8 (Security Misconfiguration) | **MASVS:** MASVS-PLATFORM
|
|
689
|
+
- **Description:** Malicious apps hijack the task stack and overlay phishing activities over legitimate apps.
|
|
690
|
+
- **Fix:** Set `android:taskAffinity=""` on activities. Use `singleTask` or `singleInstance` launch mode for sensitive activities.
|
|
691
|
+
|
|
692
|
+
### V-AND-14: Tapjacking / Overlay Attacks
|
|
693
|
+
- **Risk:** MEDIUM | **OWASP:** M8 (Security Misconfiguration) | **MASVS:** MASVS-PLATFORM
|
|
694
|
+
- **Description:** Apps with `SYSTEM_ALERT_WINDOW` overlay transparent views to intercept touches or obscure security prompts.
|
|
695
|
+
- **Fix:** Set `android:filterTouchesWhenObscured="true"`. Check `MotionEvent.FLAG_WINDOW_IS_OBSCURED` in touch handlers.
|
|
696
|
+
|
|
697
|
+
### V-AND-15: Improper Certificate Validation
|
|
698
|
+
- **Risk:** CRITICAL | **OWASP:** M5 (Insecure Communication) | **MASVS:** MASVS-NETWORK
|
|
699
|
+
- **Description:** Custom `TrustManager` implementations that accept all certificates or `HostnameVerifier` that always returns true completely disable TLS verification.
|
|
700
|
+
- **Fix:** Never implement custom TrustManagers. Use platform defaults or network security config for pinning.
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
## 5. Security Checklist
|
|
705
|
+
|
|
706
|
+
### Build and Configuration
|
|
707
|
+
- [ ] `android:debuggable` is NOT manually set (auto-managed by build variant)
|
|
708
|
+
- [ ] `android:allowBackup="false"` or restricted via `fullBackupContent`
|
|
709
|
+
- [ ] `android:usesCleartextTraffic="false"` or blocked via network security config
|
|
710
|
+
- [ ] R8/ProGuard enabled with `isMinifyEnabled = true` for release builds
|
|
711
|
+
- [ ] `isShrinkResources = true` to remove unused resources
|
|
712
|
+
- [ ] No hardcoded API keys, secrets, or credentials in source code or resources
|
|
713
|
+
- [ ] `targetSdk` set to the latest stable API level
|
|
714
|
+
- [ ] Release signing uses a strong key (RSA 2048+ or EC P-256+)
|
|
715
|
+
|
|
716
|
+
### Component Security
|
|
717
|
+
- [ ] All components explicitly declare `android:exported` (required targetSdk 31+)
|
|
718
|
+
- [ ] Internal components set `android:exported="false"`
|
|
719
|
+
- [ ] Exported components protected by `signature`-level permissions
|
|
720
|
+
- [ ] PendingIntents use `FLAG_IMMUTABLE` unless mutability is required
|
|
721
|
+
- [ ] ContentProviders use parameterized queries and validate URIs
|
|
722
|
+
- [ ] BroadcastReceivers validate sender, use `RECEIVER_NOT_EXPORTED` (Android 14+)
|
|
723
|
+
|
|
724
|
+
### Data Protection
|
|
725
|
+
- [ ] Sensitive data stored with EncryptedSharedPreferences or Keystore + Tink
|
|
726
|
+
- [ ] No sensitive data written to external storage
|
|
727
|
+
- [ ] No sensitive data in application logs (stripped via R8 rules)
|
|
728
|
+
- [ ] Clipboard auto-cleared for sensitive fields, `EXTRA_IS_SENSITIVE` flag set
|
|
729
|
+
- [ ] Database encryption (SQLCipher) for sensitive local data
|
|
730
|
+
- [ ] Cache directories cleared of sensitive data on logout
|
|
731
|
+
|
|
732
|
+
### Network Security
|
|
733
|
+
- [ ] Network security config blocks cleartext traffic
|
|
734
|
+
- [ ] Certificate pinning configured with backup pins and expiration
|
|
735
|
+
- [ ] No custom TrustManager or HostnameVerifier implementations
|
|
736
|
+
- [ ] API communication uses TLS 1.2+ exclusively
|
|
737
|
+
- [ ] Tokens transmitted only in headers, never in URLs
|
|
738
|
+
|
|
739
|
+
### Authentication and Authorization
|
|
740
|
+
- [ ] BiometricPrompt with `BIOMETRIC_STRONG` for sensitive operations
|
|
741
|
+
- [ ] Keystore keys bound to user authentication with timeout
|
|
742
|
+
- [ ] Session tokens have server-enforced expiration
|
|
743
|
+
- [ ] Re-authentication required for sensitive actions
|
|
744
|
+
|
|
745
|
+
### Runtime Protection
|
|
746
|
+
- [ ] Root/emulator detection implemented (defense-in-depth, not sole control)
|
|
747
|
+
- [ ] Play Integrity API verdict checked server-side
|
|
748
|
+
- [ ] Tamper detection (APK signature verification at runtime)
|
|
749
|
+
- [ ] Anti-debugging checks (detect JDWP attachment)
|
|
750
|
+
- [ ] WebViews hardened (no file access, restricted domains, minimal bridge)
|
|
751
|
+
|
|
752
|
+
---
|
|
753
|
+
|
|
754
|
+
## 6. Tools and Automation
|
|
755
|
+
|
|
756
|
+
### Static Analysis
|
|
757
|
+
|
|
758
|
+
| Tool | Purpose | Usage |
|
|
759
|
+
|---|---|---|
|
|
760
|
+
| **MobSF** | Automated static + dynamic analysis | `docker run -p 8000:8000 opensecurity/mobile-security-framework-mobsf` -- upload APK for report |
|
|
761
|
+
| **jadx** | DEX/APK to Java decompiler | `jadx -d output/ app.apk` -- review for hardcoded secrets |
|
|
762
|
+
| **APKTool** | APK decompilation/recompilation | `apktool d app.apk` -- inspect manifest, resources, smali |
|
|
763
|
+
| **Android Lint** | IDE-integrated static checks | `./gradlew lint` -- flags insecure WebView, exported components |
|
|
764
|
+
| **semgrep** | Pattern-based code scanning | Custom rules for Android vulnerabilities |
|
|
765
|
+
| **QARK** | Quick Android Review Kit | Automated source/APK vulnerability analysis |
|
|
766
|
+
|
|
767
|
+
### Dynamic Analysis
|
|
768
|
+
|
|
769
|
+
| Tool | Purpose | Usage |
|
|
770
|
+
|---|---|---|
|
|
771
|
+
| **Frida** | Runtime instrumentation/hooking | `frida -U -f com.example.app -l script.js` -- hook methods, bypass pinning |
|
|
772
|
+
| **drozer** | IPC attack framework | `drozer console connect` -- enumerate exported components, test injection |
|
|
773
|
+
| **Objection** | Frida-powered exploration | `objection -g com.example.app explore` -- SSL bypass, keychain dump |
|
|
774
|
+
| **Burp Suite / mitmproxy** | HTTPS traffic interception | Configure device proxy, install CA, intercept API traffic |
|
|
775
|
+
|
|
776
|
+
### Google Play Security
|
|
777
|
+
|
|
778
|
+
| Check | Description |
|
|
779
|
+
|---|---|
|
|
780
|
+
| **Play Protect** | Automated malware scanning for published and sideloaded apps |
|
|
781
|
+
| **Pre-launch reports** | Automated testing before publication (crashes, vulnerabilities) |
|
|
782
|
+
| **App signing by Google Play** | Google manages release signing keys |
|
|
783
|
+
| **Play Integrity API** | Device/app attestation for server-side verification |
|
|
784
|
+
| **Data Safety section** | Required data collection and security practices disclosure |
|
|
785
|
+
|
|
786
|
+
### CI/CD Integration
|
|
787
|
+
|
|
788
|
+
```yaml
|
|
789
|
+
# GitHub Actions security checks
|
|
790
|
+
- name: Run Android Lint
|
|
791
|
+
run: ./gradlew lint
|
|
792
|
+
|
|
793
|
+
- name: Check for hardcoded secrets
|
|
794
|
+
run: |
|
|
795
|
+
if grep -rn "api_key\|secret\|password\|token" \
|
|
796
|
+
app/src/main/res/values/strings.xml; then
|
|
797
|
+
echo "Potential secrets found in strings.xml"
|
|
798
|
+
exit 1
|
|
799
|
+
fi
|
|
800
|
+
|
|
801
|
+
- name: Verify release config
|
|
802
|
+
run: |
|
|
803
|
+
if grep -q 'android:debuggable="true"' \
|
|
804
|
+
app/src/main/AndroidManifest.xml; then
|
|
805
|
+
echo "debuggable=true found in manifest"
|
|
806
|
+
exit 1
|
|
807
|
+
fi
|
|
808
|
+
|
|
809
|
+
- name: MobSF Static Analysis
|
|
810
|
+
run: |
|
|
811
|
+
curl -F "file=@app/build/outputs/apk/release/app-release.apk" \
|
|
812
|
+
http://localhost:8000/api/v1/upload \
|
|
813
|
+
-H "Authorization: ${MOBSF_API_KEY}"
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
## 7. Platform-Specific Guidance
|
|
819
|
+
|
|
820
|
+
### 7.1 Kotlin-Specific Security Patterns
|
|
821
|
+
|
|
822
|
+
```kotlin
|
|
823
|
+
// Sealed classes for security-sensitive state machines
|
|
824
|
+
sealed class AuthState {
|
|
825
|
+
object Unauthenticated : AuthState()
|
|
826
|
+
data class Authenticated(
|
|
827
|
+
val token: String, val expiresAt: Long
|
|
828
|
+
) : AuthState()
|
|
829
|
+
object BiometricRequired : AuthState()
|
|
830
|
+
data class Error(val code: Int) : AuthState()
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Value classes prevent type confusion with sensitive strings
|
|
834
|
+
@JvmInline
|
|
835
|
+
value class AuthToken(val value: String) {
|
|
836
|
+
// Prevent accidental logging
|
|
837
|
+
override fun toString(): String = "AuthToken[REDACTED]"
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
@JvmInline
|
|
841
|
+
value class UserId(val value: String)
|
|
842
|
+
|
|
843
|
+
// Scope functions for secure cleanup
|
|
844
|
+
fun processSecret(secretBytes: ByteArray) {
|
|
845
|
+
try {
|
|
846
|
+
performCryptoOperation(secretBytes)
|
|
847
|
+
} finally {
|
|
848
|
+
secretBytes.fill(0) // Zero out secret from memory
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// Constant-time string comparison
|
|
853
|
+
fun String.secureEquals(other: String): Boolean {
|
|
854
|
+
return java.security.MessageDigest.isEqual(
|
|
855
|
+
this.toByteArray(Charsets.UTF_8),
|
|
856
|
+
other.toByteArray(Charsets.UTF_8)
|
|
857
|
+
)
|
|
858
|
+
}
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
### 7.2 Jetpack Security Library Status
|
|
862
|
+
|
|
863
|
+
As of April 2025, `androidx.security:security-crypto` (v1.1.0-alpha07) is deprecated. Official recommendation:
|
|
864
|
+
|
|
865
|
+
1. **Use Android Keystore directly** for key management
|
|
866
|
+
2. **Use Google Tink** for encryption primitives (AES-GCM, AEAD)
|
|
867
|
+
3. **Community fork** (`ed-george/encrypted-shared-preferences`) provides continued maintenance
|
|
868
|
+
|
|
869
|
+
```kotlin
|
|
870
|
+
// OLD (deprecated): EncryptedSharedPreferences
|
|
871
|
+
val masterKey = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
|
|
872
|
+
val prefs = EncryptedSharedPreferences.create(...)
|
|
873
|
+
|
|
874
|
+
// NEW (recommended): Keystore + Tink
|
|
875
|
+
val aead = SecureStorage.getAead(context) // See Section 3.2
|
|
876
|
+
val encrypted = aead.encrypt(plaintext, associatedData)
|
|
877
|
+
// Store encrypted bytes in SharedPreferences or DataStore
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
### 7.3 Android Gradle Plugin Security Configuration
|
|
881
|
+
|
|
882
|
+
```kotlin
|
|
883
|
+
// build.gradle.kts (app module)
|
|
884
|
+
android {
|
|
885
|
+
namespace = "com.example.secureapp"
|
|
886
|
+
compileSdk = 35
|
|
887
|
+
|
|
888
|
+
defaultConfig {
|
|
889
|
+
minSdk = 26 // Android 8.0+ for strong crypto defaults
|
|
890
|
+
targetSdk = 35
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
buildTypes {
|
|
894
|
+
release {
|
|
895
|
+
isMinifyEnabled = true
|
|
896
|
+
isShrinkResources = true
|
|
897
|
+
proguardFiles(
|
|
898
|
+
getDefaultProguardFile(
|
|
899
|
+
"proguard-android-optimize.txt"
|
|
900
|
+
),
|
|
901
|
+
"proguard-rules.pro"
|
|
902
|
+
)
|
|
903
|
+
signingConfig = signingConfigs.getByName("release")
|
|
904
|
+
}
|
|
905
|
+
debug {
|
|
906
|
+
buildConfigField(
|
|
907
|
+
"String", "API_BASE_URL",
|
|
908
|
+
"\"https://dev-api.example.com\""
|
|
909
|
+
)
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
packaging {
|
|
914
|
+
resources {
|
|
915
|
+
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
|
916
|
+
excludes += "DebugProbesKt.bin"
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
dependencies {
|
|
922
|
+
implementation("com.google.crypto.tink:tink-android:1.12.0")
|
|
923
|
+
implementation("androidx.biometric:biometric:1.2.0-alpha05")
|
|
924
|
+
implementation("com.google.android.play:integrity:1.5.0")
|
|
925
|
+
debugImplementation(
|
|
926
|
+
"com.squareup.leakcanary:leakcanary-android:2.14"
|
|
927
|
+
)
|
|
928
|
+
}
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
### 7.4 Play Store Security Requirements (2025)
|
|
932
|
+
|
|
933
|
+
- **Target SDK:** New apps must target Android 14 (API 34) or higher
|
|
934
|
+
- **Data Safety section:** Mandatory disclosure of data practices
|
|
935
|
+
- **App signing:** Play App Signing enrollment required for new apps
|
|
936
|
+
- **Privacy Policy:** Required for apps accessing sensitive permissions
|
|
937
|
+
- **Foreground service types:** Must declare exact service types
|
|
938
|
+
- **Photo/video permissions:** Must use photo picker or specific media permissions
|
|
939
|
+
- **Credential Manager:** Recommended for sign-in flows (replaces Smart Lock)
|
|
940
|
+
|
|
941
|
+
### 7.5 Android Version-Specific Security Features
|
|
942
|
+
|
|
943
|
+
| Version | API | Key Security Features |
|
|
944
|
+
|---|---|---|
|
|
945
|
+
| Android 10 | 29 | Scoped storage, TLS 1.3 default, background location restrictions |
|
|
946
|
+
| Android 11 | 30 | One-time permissions, auto-reset permissions, scoped storage enforcement |
|
|
947
|
+
| Android 12 | 31 | Explicit export required, approximate location, clipboard notifications |
|
|
948
|
+
| Android 13 | 33 | Photo picker, notification permissions, clipboard auto-clear, `EXTRA_IS_SENSITIVE` |
|
|
949
|
+
| Android 14 | 34 | Selected photo access, screenshot detection API, credential manager, foreground service types |
|
|
950
|
+
| Android 15 | 35 | Partial screen sharing, E2EE contact keys API, Play Protect live threat detection, temporary permissions |
|
|
951
|
+
|
|
952
|
+
---
|
|
953
|
+
|
|
954
|
+
## 8. Incident Patterns
|
|
955
|
+
|
|
956
|
+
### 8.1 Malware Detection and Response
|
|
957
|
+
|
|
958
|
+
**Detection Indicators:**
|
|
959
|
+
- Unusual battery drain or data usage (C2 communication)
|
|
960
|
+
- Apps requesting excessive permissions (accessibility, device admin)
|
|
961
|
+
- Unknown apps installed from outside Play Store
|
|
962
|
+
- Unexpected overlay prompts or login screens
|
|
963
|
+
- Device performance degradation
|
|
964
|
+
|
|
965
|
+
**Response Playbook:**
|
|
966
|
+
1. **Identify** -- Run Play Protect scan; review installed apps for unrecognized entries
|
|
967
|
+
2. **Contain** -- Enable airplane mode to cut C2 communication; revoke accessibility and device admin permissions
|
|
968
|
+
3. **Eradicate** -- Uninstall malicious app; factory reset if rootkit suspected; change all credentials
|
|
969
|
+
4. **Recover** -- Restore from known-good backup; re-enable accounts with new credentials; enable 2FA
|
|
970
|
+
5. **Lessons Learned** -- Determine infection vector; update MDM policies
|
|
971
|
+
|
|
972
|
+
### 8.2 Data Leak via Exported Components
|
|
973
|
+
|
|
974
|
+
**Scenario:** A fintech app's `TransactionHistoryProvider` is exported without permission protection. An attacker's app queries it to extract complete transaction history.
|
|
975
|
+
|
|
976
|
+
**Detection:**
|
|
977
|
+
- drozer: `drozer run app.provider.info -a com.example.fintech`
|
|
978
|
+
- MobSF flags unprotected exported components
|
|
979
|
+
- Android Lint: "Exported ContentProvider without required permission"
|
|
980
|
+
|
|
981
|
+
**Response:**
|
|
982
|
+
1. Hotfix: add `android:readPermission` with `signature` protection
|
|
983
|
+
2. Audit all exported components across modules
|
|
984
|
+
3. Add CI check: fail build on unprotected exported components
|
|
985
|
+
4. Review server logs for unusual access during exposure window
|
|
986
|
+
5. Notify affected users per data breach requirements
|
|
987
|
+
|
|
988
|
+
### 8.3 Supply Chain Attack via Malicious SDK
|
|
989
|
+
|
|
990
|
+
**Scenario:** A third-party analytics SDK is compromised and exfiltrates user data.
|
|
991
|
+
|
|
992
|
+
**Detection:**
|
|
993
|
+
- Network analysis reveals unexpected outbound connections
|
|
994
|
+
- Dependency scanning (OWASP Dependency-Check, Snyk) flags vulnerable versions
|
|
995
|
+
- Hash verification fails against known-good values
|
|
996
|
+
|
|
997
|
+
**Response:**
|
|
998
|
+
1. Pin dependency versions and verify checksums via `gradle.lockfile`
|
|
999
|
+
2. Remove compromised SDK; roll back to last known-good version
|
|
1000
|
+
3. Audit network traffic for data exfiltration
|
|
1001
|
+
4. Implement SBOM tracking
|
|
1002
|
+
5. Enable Gradle dependency verification
|
|
1003
|
+
|
|
1004
|
+
---
|
|
1005
|
+
|
|
1006
|
+
## 9. Compliance and Standards
|
|
1007
|
+
|
|
1008
|
+
### 9.1 OWASP MASVS v2.1 -- Android Focus
|
|
1009
|
+
|
|
1010
|
+
| Control Area | Android Considerations |
|
|
1011
|
+
|---|---|
|
|
1012
|
+
| **MASVS-STORAGE** | Keystore+Tink encryption, backup restrictions, no external storage for secrets, log stripping |
|
|
1013
|
+
| **MASVS-CRYPTO** | Android Keystore for keys, AES-256-GCM symmetric, avoid custom crypto |
|
|
1014
|
+
| **MASVS-AUTH** | BiometricPrompt with BIOMETRIC_STRONG, Credential Manager, session mgmt |
|
|
1015
|
+
| **MASVS-NETWORK** | Network security config, certificate pinning, TLS 1.2+ |
|
|
1016
|
+
| **MASVS-PLATFORM** | Component export controls, intent validation, WebView hardening, PendingIntent immutability |
|
|
1017
|
+
| **MASVS-CODE** | R8 obfuscation, anti-tampering, input validation, dependency management |
|
|
1018
|
+
| **MASVS-RESILIENCE** | Root detection, Play Integrity, debugger detection, emulator detection |
|
|
1019
|
+
| **MASVS-PRIVACY** | Scoped permissions, data minimization, privacy dashboard compliance |
|
|
1020
|
+
|
|
1021
|
+
### 9.2 OWASP Mobile Top 10 (2024) -- Android Mitigations
|
|
1022
|
+
|
|
1023
|
+
| # | Risk | Android Mitigation |
|
|
1024
|
+
|---|---|---|
|
|
1025
|
+
| M1 | Improper Credential Usage | Keystore for secrets, no hardcoded keys, server-side token management |
|
|
1026
|
+
| M2 | Inadequate Supply Chain Security | Dependency verification, SBOM, version pinning, Gradle lockfiles |
|
|
1027
|
+
| M3 | Insecure Authentication/Authorization | BiometricPrompt, Credential Manager, server-enforced authorization |
|
|
1028
|
+
| M4 | Insufficient Input/Output Validation | Parameterized queries, intent validation, WebView URL filtering |
|
|
1029
|
+
| M5 | Insecure Communication | Network security config, certificate pinning, no cleartext |
|
|
1030
|
+
| M6 | Inadequate Privacy Controls | Scoped permissions, photo picker, data minimization |
|
|
1031
|
+
| M7 | Insufficient Binary Protections | R8/ProGuard, Play Integrity, tamper detection |
|
|
1032
|
+
| M8 | Security Misconfiguration | Explicit exports, backup restrictions, debug mode checks |
|
|
1033
|
+
| M9 | Insecure Data Storage | Keystore+Tink, SQLCipher, log stripping |
|
|
1034
|
+
| M10 | Insufficient Cryptography | Hardware-backed Keystore, AES-256-GCM, Tink |
|
|
1035
|
+
|
|
1036
|
+
### 9.3 Additional Compliance Frameworks
|
|
1037
|
+
|
|
1038
|
+
- **PCI DSS v4.0** -- Payment apps: encrypted storage, secure communication, access controls
|
|
1039
|
+
- **HIPAA** -- Health apps: encryption at rest/transit, audit logging, access controls
|
|
1040
|
+
- **GDPR** -- EU user data: data minimization, right to erasure, consent management
|
|
1041
|
+
- **Google MASA** -- App Defense Alliance validation against MASVS Level 1; passing apps get Play Store security badge
|
|
1042
|
+
|
|
1043
|
+
---
|
|
1044
|
+
|
|
1045
|
+
## 10. Code Examples -- Insecure vs. Secure Pairs
|
|
1046
|
+
|
|
1047
|
+
### Example 1: Storing Authentication Tokens
|
|
1048
|
+
|
|
1049
|
+
```kotlin
|
|
1050
|
+
// --- INSECURE ---
|
|
1051
|
+
fun saveToken(context: Context, token: String) {
|
|
1052
|
+
val prefs = context.getSharedPreferences(
|
|
1053
|
+
"auth", Context.MODE_PRIVATE
|
|
1054
|
+
)
|
|
1055
|
+
prefs.edit().putString("access_token", token).apply()
|
|
1056
|
+
// Plaintext in /data/data/<pkg>/shared_prefs/auth.xml
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// --- SECURE ---
|
|
1060
|
+
fun saveTokenSecurely(context: Context, token: String) {
|
|
1061
|
+
val aead = SecureStorage.getAead(context)
|
|
1062
|
+
val encrypted = aead.encrypt(
|
|
1063
|
+
token.toByteArray(Charsets.UTF_8),
|
|
1064
|
+
"auth_token".toByteArray()
|
|
1065
|
+
)
|
|
1066
|
+
val prefs = context.getSharedPreferences(
|
|
1067
|
+
"auth_enc", Context.MODE_PRIVATE
|
|
1068
|
+
)
|
|
1069
|
+
prefs.edit().putString(
|
|
1070
|
+
"access_token",
|
|
1071
|
+
android.util.Base64.encodeToString(
|
|
1072
|
+
encrypted, android.util.Base64.NO_WRAP
|
|
1073
|
+
)
|
|
1074
|
+
).apply()
|
|
1075
|
+
}
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
### Example 2: Network Configuration
|
|
1079
|
+
|
|
1080
|
+
```xml
|
|
1081
|
+
<!-- INSECURE: Cleartext allowed -->
|
|
1082
|
+
<application android:usesCleartextTraffic="true" />
|
|
1083
|
+
|
|
1084
|
+
<!-- SECURE: Strict network security config -->
|
|
1085
|
+
<application
|
|
1086
|
+
android:networkSecurityConfig="@xml/network_security_config" />
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
```xml
|
|
1090
|
+
<!-- res/xml/network_security_config.xml -->
|
|
1091
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
1092
|
+
<network-security-config>
|
|
1093
|
+
<base-config cleartextTrafficPermitted="false">
|
|
1094
|
+
<trust-anchors>
|
|
1095
|
+
<certificates src="system" />
|
|
1096
|
+
</trust-anchors>
|
|
1097
|
+
</base-config>
|
|
1098
|
+
<domain-config>
|
|
1099
|
+
<domain includeSubdomains="true">api.example.com</domain>
|
|
1100
|
+
<pin-set expiration="2026-12-31">
|
|
1101
|
+
<pin digest="SHA-256">SPKI_HASH_PRIMARY=</pin>
|
|
1102
|
+
<pin digest="SHA-256">SPKI_HASH_BACKUP=</pin>
|
|
1103
|
+
</pin-set>
|
|
1104
|
+
</domain-config>
|
|
1105
|
+
</network-security-config>
|
|
1106
|
+
```
|
|
1107
|
+
|
|
1108
|
+
### Example 3: Secure Activity for Payments
|
|
1109
|
+
|
|
1110
|
+
```kotlin
|
|
1111
|
+
// --- INSECURE ---
|
|
1112
|
+
// Exported implicitly via intent-filter, no protections
|
|
1113
|
+
// <activity android:name=".PaymentActivity">
|
|
1114
|
+
// <intent-filter>
|
|
1115
|
+
// <action android:name="com.example.PAY" />
|
|
1116
|
+
// </intent-filter>
|
|
1117
|
+
// </activity>
|
|
1118
|
+
|
|
1119
|
+
// --- SECURE ---
|
|
1120
|
+
// <activity
|
|
1121
|
+
// android:name=".PaymentActivity"
|
|
1122
|
+
// android:exported="false"
|
|
1123
|
+
// android:taskAffinity=""
|
|
1124
|
+
// android:excludeFromRecents="true" />
|
|
1125
|
+
|
|
1126
|
+
class PaymentActivity : AppCompatActivity() {
|
|
1127
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
1128
|
+
super.onCreate(savedInstanceState)
|
|
1129
|
+
// Prevent screenshots and screen recording
|
|
1130
|
+
window.setFlags(
|
|
1131
|
+
WindowManager.LayoutParams.FLAG_SECURE,
|
|
1132
|
+
WindowManager.LayoutParams.FLAG_SECURE
|
|
1133
|
+
)
|
|
1134
|
+
verifyAppIntegrity()
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
|
1138
|
+
// Tapjacking protection
|
|
1139
|
+
if (event?.flags?.and(
|
|
1140
|
+
MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0
|
|
1141
|
+
) {
|
|
1142
|
+
return false
|
|
1143
|
+
}
|
|
1144
|
+
return super.onTouchEvent(event)
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
private fun verifyAppIntegrity() {
|
|
1148
|
+
val expectedSig = "expected_sha256_of_signing_cert"
|
|
1149
|
+
val packageInfo = packageManager.getPackageInfo(
|
|
1150
|
+
packageName,
|
|
1151
|
+
PackageManager.GET_SIGNING_CERTIFICATES
|
|
1152
|
+
)
|
|
1153
|
+
val signatures = packageInfo.signingInfo
|
|
1154
|
+
?.apkContentsSigners ?: return finish()
|
|
1155
|
+
val currentSig = signatures.first().toByteArray()
|
|
1156
|
+
val digest = java.security.MessageDigest
|
|
1157
|
+
.getInstance("SHA-256").digest(currentSig)
|
|
1158
|
+
val hash = digest.joinToString("") { "%02x".format(it) }
|
|
1159
|
+
if (hash != expectedSig) { finish() }
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
```
|
|
1163
|
+
|
|
1164
|
+
### Example 4: Intent Handling
|
|
1165
|
+
|
|
1166
|
+
```kotlin
|
|
1167
|
+
// --- INSECURE ---
|
|
1168
|
+
class DeepLinkActivity : AppCompatActivity() {
|
|
1169
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
1170
|
+
super.onCreate(savedInstanceState)
|
|
1171
|
+
val url = intent.getStringExtra("url")
|
|
1172
|
+
webView.loadUrl(url!!) // Arbitrary URL -- XSS risk
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// --- SECURE ---
|
|
1177
|
+
class DeepLinkActivity : AppCompatActivity() {
|
|
1178
|
+
private val ALLOWED_HOSTS = setOf(
|
|
1179
|
+
"app.example.com", "help.example.com"
|
|
1180
|
+
)
|
|
1181
|
+
|
|
1182
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
1183
|
+
super.onCreate(savedInstanceState)
|
|
1184
|
+
val url = intent.getStringExtra("url")
|
|
1185
|
+
if (url == null || !isUrlAllowed(url)) {
|
|
1186
|
+
finish()
|
|
1187
|
+
return
|
|
1188
|
+
}
|
|
1189
|
+
webView.loadUrl(url)
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
private fun isUrlAllowed(url: String): Boolean {
|
|
1193
|
+
return try {
|
|
1194
|
+
val uri = android.net.Uri.parse(url)
|
|
1195
|
+
uri.scheme == "https" && uri.host in ALLOWED_HOSTS
|
|
1196
|
+
} catch (e: Exception) { false }
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
---
|
|
1202
|
+
|
|
1203
|
+
## References
|
|
1204
|
+
|
|
1205
|
+
- [OWASP Mobile Top 10 2024](https://owasp.org/www-project-mobile-top-10/2023-risks/)
|
|
1206
|
+
- [OWASP MASVS v2.1](https://mas.owasp.org/MASVS/)
|
|
1207
|
+
- [OWASP MASTG](https://mas.owasp.org/)
|
|
1208
|
+
- [Android Developer Security Docs](https://developer.android.com/privacy-and-security)
|
|
1209
|
+
- [Android Keystore System](https://developer.android.com/privacy-and-security/keystore)
|
|
1210
|
+
- [Android Network Security Config](https://developer.android.com/privacy-and-security/security-config)
|
|
1211
|
+
- [Play Integrity API](https://developer.android.com/google/play/integrity)
|
|
1212
|
+
- [NowSecure: Android 15 Security](https://www.nowsecure.com/blog/2024/07/31/comprehensive-guide-to-android-15-security-and-privacy-improvements/)
|
|
1213
|
+
- [Cleafy Labs: SharkBot](https://www.cleafy.com/cleafy-labs/sharkbot-a-new-generation-of-android-trojan-is-targeting-banks-in-europe)
|
|
1214
|
+
- [ThreatFabric: Vultur](https://thehackernews.com/2024/04/vultur-android-banking-trojan-returns.html)
|
|
1215
|
+
- [iVerify: Pegasus 2024](https://iverify.io/blog/iverify-mobile-threat-investigation-uncovers-new-pegasus-samples)
|
|
1216
|
+
- [MobSF](https://github.com/MobSF/Mobile-Security-Framework-MobSF)
|
|
1217
|
+
- [Jetpack Security Deprecation](https://marcobrador.medium.com/on-the-deprecation-of-jetsec-crypto-dea9205d5076)
|
|
1218
|
+
- [App Defense Alliance MASA](https://appdefensealliance.dev/masa)
|