agentleFS
GuillemRocaGuillemRoca/agent-skills-android/skills/security-and-hardening/SKILL.md

security-and-hardening

Skill2 starsChanged 41 days agoMITView on GitHub

Use when handling sensitive data, authentication, network communication, or before shipping to the Play Store. Three-tier framework (Always Do, Ask First, Never Do) with Android-specific security patterns, plus data privacy and compliance (GDPR/CCPA, Play Data safety, account deletion).

  • Reads credentials

88 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use test-strategy, verification-before-completion and 3 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • jarosser06Skill

    test-strategy

    Plans pytest test strategies for Drift's 90%+ coverage requirement using coverage analysis, edge case identification, and test suite design. Use when determining what tests to write, analyzing coverage gaps, or planning test strategies.

    Also in 3 projects that use this

  • OpenAISkill

    verification-before-completion

    Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always

    Also in 9 projects that use this

  • silvainfmSkill

    marketing-ideas

    When the user needs marketing ideas, inspiration, or strategies for their SaaS or software product. Also use when the user asks for 'marketing ideas,' 'growth ideas,' 'how to market,' 'marketing strategies,' 'marketing tactics,' 'ways to promote,' or 'ideas to grow.' This skill provides 140 proven marketing approaches organized by category.

    Also in 3 projects that use this

  • OpenAISkill

    using-git-worktrees

    Use when starting feature work that needs isolation from current workspace or before executing implementation plans - ensures an isolated workspace exists via native tools or git worktree fallback

    Also in 5 projects that use this

  • CloudflareSkill

    receiving-code-review

    Use when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation

    Also in 5 projects that use this

The file

We split this skill into the rules it gives an agent

4 rules. 0 are common, 3 are distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 83 edited versions we read keep these.

  • 3

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before shipping any release to the Play Store

    line 20
  2. Very specific:

    Minimize permissions: Prefer the Photo Picker (ActivityResultContracts.PickVisualMedia) over READ_MEDIA_IMAGES, ACCESS_COARSE_LOCATION over …

    line 243
  3. Distinctive:

    No Network Security Config

    line 293
  4. Distinctive:

    No ProGuard/R8 in release builds

    line 298

“Common” is measured: kept by at least 6 in 10 of the 83 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Security and Hardening

Overview

Security is a development constraint, not an afterthought. This skill provides a three-tier framework — Always Do, Ask First, Never Do — covering the OWASP Mobile Top 10, Android-specific attack vectors, and hardening patterns for production apps.

When to Use

  • Handling user credentials, tokens, or personal data
  • Implementing network communication
  • Before shipping any release to the Play Store
  • Reviewing code that touches authentication or authorization
  • Setting up ProGuard/R8 rules
  • Implementing WebView features
  • Collecting personal data, adding analytics/ads SDKs, or answering privacy requirements (GDPR, CCPA, Play Data safety)

Skip when: Changes are purely cosmetic with no data or network impact.

Core Process: Three-Tier Framework

Always Do

  1. Secure data storage. Jetpack Security Crypto (EncryptedSharedPreferences/MasterKey) is deprecated and unmaintained — do not add it to new code. Encrypt with a key held in the Android Keystore and persist the ciphertext (DataStore or a file):
// Key lives in the Android Keystore — never leaves secure hardware
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
keyGenerator.init(
    KeyGenParameterSpec.Builder("auth_token_key", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
        .build()
)
val secretKey = keyGenerator.generateKey()

// Encrypt, then persist iv + ciphertext (e.g. in Proto DataStore)
val cipher = Cipher.getInstance("AES/GCM/NoPadding").apply { init(Cipher.ENCRYPT_MODE, secretKey) }
val encrypted = cipher.iv + cipher.doFinal(token.toByteArray())

Existing apps already on EncryptedSharedPreferences can keep it (the format is stable), but plan a migration and never store new categories of secrets with it.

  1. Network Security Config:
<!-- res/xml/network_security_config.xml -->
<network-security-config>
    <!-- Enforce HTTPS for all connections -->
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>

    <!-- Certificate pinning for your API -->
    <domain-config>
        <domain includeSubdomains="true">api.example.com</domain>
        <pin-set expiration="2025-12-31">
            <pin digest="SHA-256">base64EncodedPin=</pin>
            <!-- Backup pin -->
            <pin digest="SHA-256">base64EncodedBackupPin=</pin>
        </pin-set>
    </domain-config>
</network-security-config>
<!-- AndroidManifest.xml -->
<application android:networkSecurityConfig="@xml/network_security_config">

Targeting API 37 (Android 17) also changes the network/auth surface: LAN access requires the ACCESS_LOCAL_NETWORK permission, standard SMS OTPs are delayed 3 hours (use the SMS Retriever API or SMS User Consent instead of reading raw SMS), and Encrypted Client Hello + Certificate Transparency are on by default for TLS — verify pinning still works.

  1. Input validation:
// Validate all external input
fun processDeepLink(uri: Uri): DeepLinkResult {
    val taskId = uri.getQueryParameter("taskId")
        ?: return DeepLinkResult.Invalid("Missing taskId")

    // Validate format
    if (!taskId.matches(Regex("^[a-zA-Z0-9-]{1,36}$"))) {
        return DeepLinkResult.Invalid("Invalid taskId format")
    }

    return DeepLinkResult.Valid(taskId)
}
  1. Intent validation for exported components:
// Validate intents for exported Activities/Receivers
class TaskDeepLinkActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val intent = intent ?: run { finish(); return }

        // Validate the source and data
        val taskId = intent.data?.getQueryParameter("taskId")
        if (taskId == null || !isValidTaskId(taskId)) {
            finish()
            return
        }
        // Process valid deep link
    }
}

Deeper audits: android-skills:android-intent-security and android-skills:android-permissions-security (optional Google companion plugin, see README).

  1. Secrets management:
# local.properties (NEVER committed to git)
API_KEY=your_secret_key_here
// build.gradle.kts
val localProperties = Properties().apply {
    val file = rootProject.file("local.properties")
    if (file.exists()) load(file.inputStream())
}

android {
    defaultConfig {
        buildConfigField("String", "API_KEY",
            "\"${localProperties.getProperty("API_KEY", "")}\"")
    }
}
# .gitignore
local.properties
*.jks
*.keystore
  1. Remove debug code for release:
// build.gradle.kts — strip Log calls in release
buildTypes {
    release {
        isMinifyEnabled = true
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
    }
}

// proguard-rules.pro
-assumenosideeffects class android.util.Log {
    public static int d(...);
    public static int v(...);
}

Ask First

  1. Changes that require review:
    • Modifying authentication or authorization logic
    • Adding new exported components (Activities, Receivers, Providers)
    • Changing certificate pinning configuration
    • Adding new permissions to AndroidManifest
    • Integrating new third-party SDKs
    • Implementing WebView with JavaScript enabled
    • Modifying ProGuard/R8 rules
    • Changing data encryption or storage approach

Never Do

  1. Absolute prohibitions:
NeverWhy
Commit secrets to gitSecrets in git history are permanent, even after removal
Log sensitive data (Log.d with tokens)Logcat is accessible to other apps on rooted devices
Trust client-side validation aloneAll client validation can be bypassed
Use MODE_WORLD_READABLEAny app can read your files
Enable cleartext traffic in productionData interceptable on network
Store passwords in plain textUse EncryptedSharedPreferences or Android Keystore
Use WebView.setJavaScriptEnabled(true) without sanitizingXSS attacks via injected content
Export components without android:permissionAny app can invoke them
Disable certificate verificationMan-in-the-middle attacks
Use FLAG_SECURE to prevent screenshots AND log sensitive dataInconsistent security posture

WebView Security

  1. If you must use WebView:
webView.settings.apply {
    javaScriptEnabled = true // Only if necessary
    allowFileAccess = false
    allowContentAccess = false
    domStorageEnabled = true

    // Restrict to your domain
    setSupportMultipleWindows(false)
}

webView.webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
        val url = request.url
        // Only allow your trusted domains
        return url.host != "trusted.example.com"
    }
}

// Never add JavaScript interfaces that expose sensitive operations
// webView.addJavascriptInterface(dangerousObject, "Android") // DON'T

Data Privacy & Compliance

  1. Hold less, for less time. Security asks "can an attacker read it?"; privacy asks "should we hold it at all, and for how long?" Data never collected cannot be breached, mis-declared, or missed in a deletion. Classify every field as you add it:
ClassAndroid examplesHandling
Non-personalAggregate counts, app version, crash-free rateNormal handling
Personal (PII)Name, email, IP, user ID, advertising ID, Android ID / other device IDsMinimize, access-control, include in export/delete, declare in Data safety
SensitivePrecise location, health, biometrics, contacts, photos/media, financial data, anything about minorsExplicit basis or consent, Keystore-backed encryption, never in cloud backup or logs

Operating rules:

  • Collect against a stated purpose. "Might be useful later" is breach scope, not a purpose. Don't log PII — observability-and-instrumentation covers log hygiene.
  • Minimize permissions. Prefer the Photo Picker (ActivityResultContracts.PickVisualMedia) over READ_MEDIA_IMAGES, ACCESS_COARSE_LOCATION over ACCESS_FINE_LOCATION, and system pickers/intents over broad read permissions. Every permission you don't hold is data you can't leak.
  • Gate SDKs on consent. Analytics, ads, and attribution SDKs must not start collecting in Application.onCreate before the user has chosen. Default collection off, then enable from the consent result:
// AndroidManifest.xml: <meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />
fun applyConsent(analytics: FirebaseAnalytics, granted: Boolean) {
    val status = if (granted) ConsentStatus.GRANTED else ConsentStatus.DENIED
    analytics.setConsent(mapOf(ConsentType.ANALYTICS_STORAGE to status, ConsentType.AD_STORAGE to status))
    analytics.setAnalyticsCollectionEnabled(granted)
}
  • Declare what you actually ship. The Play Data safety form must match real collection, including every third-party SDK (analytics, ads, crash reporting, attribution). Check each SDK's own data-disclosure docs and re-check the form whenever an SDK is added or upgraded.
  • Account deletion is a Play requirement. Apps that let users create an account must offer deletion both in-app and via a web link listed in Play Console, and deleting the account must delete (or anonymize) its associated data — not just flip an isDeleted flag.
  • Set retention and make deletion reach every copy. On sign-out or account deletion, clear Room tables, DataStore, files and caches, cancel WorkManager jobs whose input data carries personal payloads, and trigger server-side and analytics-vendor deletion. Exclude tokens, PII, and anything bound to a Keystore key (undecryptable after restore anyway) from Auto Backup — android:dataExtractionRules for API 31+, android:fullBackupContent for API 30 and below. Set both if minSdk < 31.
  • Design data-subject rights into the schema. GDPR/CCPA export, correction, and deletion are engineering features: key personal data by user ID so it is findable and erasable, not smeared across denormalized tables, blobs, and logs.
  • Make policy configurable by region. Consent requirements and residency rules differ by user location — keep them behind a config boundary rather than hardcoding one jurisdiction.

OWASP Mobile Top 10 Quick Reference

#RiskAndroid Mitigation
M1Improper Credential UsageAndroid Keystore, EncryptedSharedPreferences
M2Inadequate Supply Chain SecurityDependency verification, version pinning
M3Insecure AuthenticationBiometricPrompt, OAuth2 with PKCE
M4Insufficient Input/Output ValidationValidate deep links, intents, API responses
M5Insecure CommunicationNetwork Security Config, cert pinning
M6Inadequate Privacy ControlsMinimize data collection, respect permissions
M7Insufficient Binary ProtectionsR8/ProGuard, tamper detection
M8Security MisconfigurationReview manifest, disable debuggable in release
M9Insecure Data StorageEncryptedSharedPreferences, Room with encryption
M10Insufficient CryptographyAndroid Keystore for key management

Common Rationalizations

ShortcutWhy It Fails
"It's just a debug key, I'll change it later"Debug keys committed to git stay in history forever.
"Our API already validates input"Client validation improves UX; server validation prevents exploits. Both needed.
"We don't need cert pinning for v1"v1 is when MITM attacks are most damaging — no monitoring to detect them.
"ProGuard breaks too many things"Configure it properly with @Keep annotations. The security cost of skipping is higher.
"Collect it now, we might need it later"Data you don't hold can't be breached or mis-declared. "Might need it" is breach scope, not a purpose.
"The SDK handles its own privacy"You declare its collection in Data safety and you answer for it. Gate it on consent and read its disclosure docs.
"Delete account = mark the user deleted"Play requires the associated data to be deleted. Local DBs, backups, queued work, and vendor copies all hold it.

Red Flags

  • Secrets (API keys, tokens) in source code
  • android:debuggable="true" in release manifest
  • clearTextTrafficPermitted="true" in production
  • No Network Security Config
  • Log.d with user data or tokens
  • MODE_WORLD_READABLE or MODE_WORLD_WRITEABLE
  • Exported components without permission checks
  • WebView with unrestricted JavaScript
  • No ProGuard/R8 in release builds
  • Disabled certificate verification
  • Analytics/ads SDK initialized in Application.onCreate before consent is captured
  • New SDK or permission added without a Data safety form update
  • Account deletion that only flips a flag, or no web deletion link
  • READ_MEDIA_IMAGES / ACCESS_FINE_LOCATION where the Photo Picker / coarse location would do
  • Auth tokens or PII included in Auto Backup (no dataExtractionRules / fullBackupContent)

Verification

  • No secrets in source code (grep for API keys, tokens, passwords)
  • Network Security Config present and enforces HTTPS
  • Certificate pinning for production API
  • EncryptedSharedPreferences for sensitive data
  • Input validated at all system boundaries
  • Exported components have permission checks
  • ProGuard/R8 enabled for release builds
  • Debug logging stripped in release (ProGuard rules)
  • local.properties in .gitignore
  • android:debuggable not set (defaults to false for release)
  • WebView (if used) restricts domains and JavaScript exposure
  • Every personal-data field classified and tied to a stated purpose
  • Analytics/ads SDKs collect nothing before consent (verify with a network inspector on a fresh install)
  • Data safety form matches actual collection, including third-party SDKs
  • Account deletion works in-app and via web link, and removes local, backup, queued, server, and vendor copies
  • Backup rules exclude tokens/PII for both API 31+ and API 30-and-below paths

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.