AgentStack
SKILL verified MIT Self-run

Security And Hardening

skill-guillemroca-agent-skills-android-security-and-hardening · by GuillemRoca

>-

No reviews yet
0 installs
1 views
0.0% view→install

Install

$ agentstack add skill-guillemroca-agent-skills-android-security-and-hardening

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Security And Hardening? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

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

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:

    
    
        
            
        
    

    
    
        api.example.com
        
            base64EncodedPin=
            
            base64EncodedBackupPin=
        
    

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
    }
}
  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:

| Never | Why | |-------|-----| | Commit secrets to git | Secrets 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 alone | All client validation can be bypassed | | Use MODE_WORLD_READABLE | Any app can read your files | | Enable cleartext traffic in production | Data interceptable on network | | Store passwords in plain text | Use EncryptedSharedPreferences or Android Keystore | | Use WebView.setJavaScriptEnabled(true) without sanitizing | XSS attacks via injected content | | Export components without android:permission | Any app can invoke them | | Disable certificate verification | Man-in-the-middle attacks | | Use FLAG_SECURE to prevent screenshots AND log sensitive data | Inconsistent 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

OWASP Mobile Top 10 Quick Reference

| # | Risk | Android Mitigation | |---|------|-------------------| | M1 | Improper Credential Usage | Android Keystore, EncryptedSharedPreferences | | M2 | Inadequate Supply Chain Security | Dependency verification, version pinning | | M3 | Insecure Authentication | BiometricPrompt, OAuth2 with PKCE | | M4 | Insufficient Input/Output Validation | Validate deep links, intents, API responses | | M5 | Insecure Communication | Network Security Config, cert pinning | | M6 | Inadequate Privacy Controls | Minimize data collection, respect permissions | | M7 | Insufficient Binary Protections | R8/ProGuard, tamper detection | | M8 | Security Misconfiguration | Review manifest, disable debuggable in release | | M9 | Insecure Data Storage | EncryptedSharedPreferences, Room with encryption | | M10 | Insufficient Cryptography | Android Keystore for key management |

Common Rationalizations

| Shortcut | Why 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. |

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

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

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.