Privacy by design
Skill almasumdev/awesome-mobile-security-agent-skills/.github/skills/privacy/privacy-by-design
Privacy-by-design principles on mobile — data minimization, purpose binding, consent. Use when introducing new data collection or third-party SDKs.From its SKILL.md
npx -y skills add almasumdev/awesome-mobile-security-agent-skills --skill privacy-by-designAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.0 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
Privacy by Design
Instructions
Privacy by Design is an engineering posture, not a legal afterthought. Decisions made in the first week of a feature outweigh months of compliance paperwork.
1. The Three Questions
Before adding any data collection, answer in the PR description:
- What exactly are we collecting (field list, types, precision)?
- Why — which user-facing feature does it enable?
- For how long — retention and deletion policy.
If you can't answer cleanly, don't add it.
2. Data Minimization
Collect the least-precise data that still makes the feature work:
- Location: need it only for "find nearest store"? Use
CLLocationManagerat reduced accuracy (desiredAccuracy = kCLLocationAccuracyKilometer) or Android'sPRIORITY_BALANCED_POWER_ACCURACY. Consider iOS 14+ approximate location (requestWhenInUseAuthorization+ user choice). - Contacts: need a phone number only to check membership? Hash client-side, ping server with prefix-truncated hashes (k-anonymity) — don't upload the full contact book.
- Photos: use the PhotoPicker (
PHPickerViewControlleron iOS,ActivityResultContracts.PickVisualMediaon Android) — you get the chosen asset without full library access.
var config = PHPickerConfiguration(photoLibrary: .shared())
config.selectionLimit = 1
config.filter = .images
let picker = PHPickerViewController(configuration: config)
// No Photos permission prompt required for this path.
val launcher = registerForActivityResult(
ActivityResultContracts.PickVisualMedia()
) { uri -> /* process one image; no READ_MEDIA_IMAGES needed */ }
launcher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)
3. Purpose Binding
- Each data field has one documented purpose.
- Reuse for a new purpose requires a new consent event, not a silent expansion.
- Analytics events that "might be useful later" are a red flag; collect when you have a concrete use.
4. On-Device Over Off-Device
- Perform processing on-device when feasible (ML classification, thumbnailing, redaction).
- Ship only derived / aggregate signals off-device.
- Apple's App Store policy, Google's Play Data Safety, and GDPR all reward this architecturally.
5. Identifiers
| Identifier | Use with caution |
|---|---|
| IDFA / GAID | Advertising only; needs ATT on iOS, UMP consent on EEA Android. |
ASIdentifierManager / advertising ID | Same as above. |
UIDevice.identifierForVendor / Settings.Secure.ANDROID_ID | Scoped identifiers; still PII under GDPR. |
| Server-issued user ID | Prefer this for analytics / crash correlation. |
| IMEI / MAC / serial | Do not use on modern OSes; restricted and often unavailable. |
Use the weakest identifier that works. Generate a random install ID scoped to your app (UUID.randomUUID() stored in Keychain / Keystore) for things like A/B bucketing.
6. Third-Party SDKs
Each SDK added is a data-sharing decision:
- Enumerate what it sends (many SDKs send IP, install ID, app events by default).
- Add to Apple's Privacy Manifest (
PrivacyInfo.xcprivacy) and Google Play's Data Safety form. - Prefer SDKs that support delayed initialization until after consent.
- Audit at least yearly — SDKs expand scope between releases.
7. Logs, Crash Reports, Analytics
These are the three places PII leaks most often.
- Never log raw request / response bodies with user data in release builds.
- Strip PII from crash reports (stack traces are fine; user input in a
toString()is not). - For analytics, log categories ("filter_applied") not content ("searched for: [email protected]").
// Don't
Timber.d("User profile: $profile")
// Do
Timber.d("Loaded profile uid=${profile.id.hashPrefix(8)}")
8. Default Settings
- Telemetry / crash reporting: opt-in in regulated regions, clearly disclosed elsewhere.
- Personalization / recommendations that rely on behavior: opt-in.
- Background location, microphone, camera: never "always" by default.
9. Data Export and Deletion
Shipping a feature → shipping an export path and a delete path. Build them alongside, not after launch. See gdpr-mobile.
Checklist
- Every new field has a documented purpose and retention period.
- Location / photos / contacts use the least-privileged API (reduced accuracy, PhotoPicker, hashed lookup).
- No feature reuses data for a new purpose without fresh consent.
- Processing happens on-device where feasible.
- Identifiers used are the weakest that work; no deprecated hardware identifiers.
- Every third-party SDK is entered in the iOS Privacy Manifest and Play Data Safety form.
- Logs, crash reports, and analytics do not carry raw PII.
- Export and delete paths ship with the feature, not later.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.