v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
HIGH AI PREVALENCE: HIGH auth.xml.android.hardcoded-secret-strings

A credential (client secret, API key, password, bearer token) is hard-coded as a value in res/values/strings.xml.

Why AI tools produce this: AI coding tools generate this anti-pattern by default, it appears in a large share of AI-written auth code.

Why this matters

String resources are compiled verbatim into the APK and are recovered in seconds by unzipping/decompiling the app, so any secret placed here is effectively public (CWE-798). AI-generated Android code drops secrets into strings.xml because it is the "official" place for constants.

A public mobile client should hold no client secret at all (use PKCE). For an unavoidable key, inject it at build time via BuildConfig / Gradle properties or fetch it from a backend at runtime, never commit it as a string resource. Note: a public client_id and OAuth scope list are not secrets and are intentionally not flagged.

VULNERABLE
vulnerable.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- ruleid: auth.xml.android.hardcoded-secret-strings -->
    <string name="client_secret">aRq83Kd9sLp2mZx7Qw1nB4vT</string>
    <!-- ruleid: auth.xml.android.hardcoded-secret-strings -->
    <string name="api_key">sk_live_9f83jd0292kfovnw83hd</string>
    <!-- ruleid: auth.xml.android.hardcoded-secret-strings -->
    <string name="google_maps_api_key">AIzaSyD-9tSrke72PouQMnMX-a7eZSW0jkFMBWY</string>
</resources>
SAFE
safe.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- public identifier, not a secret: safe -->
    <string name="oauth_client_id">1234567890-abcdefg.apps.googleusercontent.com</string>
    <!-- scope list is public: safe -->
    <string name="oauth_scope">openid profile email offline_access</string>
    <!-- app name: safe -->
    <string name="app_name">Example App</string>
    <!-- short value below the secret-length floor: safe -->
    <string name="token_label">Token</string>
</resources>

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

// oauthlint-disable-next-line auth.xml.android.hardcoded-secret-strings -- <reason>

References

https://developer.android.com/privacy-and-security/security-tips#UserData ↗https://cwe.mitre.org/data/definitions/798.html ↗