App Store

    Does Apple review check for hardcoded AWS credentials?

    AWS credentials in iOS apps and Apple review

    The reader I am writing for is an iOS developer with an AWS-backed app, a pile of credentials scattered across the codebase, and uncertainty about which ones Apple will catch during review. This page sorts the AWS credential types by danger, explains what Apple does and does not check, and points at the IAM patterns that remove the risk at the architectural layer.

    Short answer

    Apple App Review does not systematically scan IPA binaries for AWS credentials of any type. Long-lived IAM access keys (prefix AKIA), short-lived session tokens (prefix ASIA), root account keys, and the matching aws_secret_access_key strings all pass through review unflagged. According to AWS's official IAM best practices documentation, long-lived credentials should not be embedded in applications at all. The architectural answer is short-lived per-user credentials issued through AWS STS AssumeRoleWithWebIdentity or Amazon Cognito Identity Pools.

    What you should know

    • AWS publishes prefix patterns for every credential type. AKIA for IAM access keys, ASIA for STS session tokens, aws_secret_access_key for the matching secret.
    • Root account keys are the worst failure mode. They grant unrestricted access to billing, IAM, and every service. AWS recommends never creating them.
    • Apple's review does not look at any of these patterns. The review process is policy-focused, not security-focused.
    • The Cognito Identity Pool pattern is the official AWS recommendation for mobile apps that need AWS access without embedded credentials.
    • IAM least-privilege is the second layer. Even when credentials are issued correctly, the IAM role's policy bounds what an attacker who steals the token can do.

    What does Apple's review look for, and not look for?

    Apple's App Review focuses on the published guideline categories: safety, performance, business, design, and legal. Per the App Review section of developer.apple.com, submissions pass an automated layer followed by a human reviewer.

    Developer reports of the automated layer suggest it catches private API usage, prohibited frameworks, missing entitlements, and obvious metadata violations. None of those checks involve running strings against the Mach-O executable. The human reviewer opens the app on a device and tests user flows; they do not decompile the binary or scan for credential patterns.

    The relevant guideline section, 5.1.1 of the App Review Guidelines, assigns developers responsibility for protecting any user data they collect. The wording does not commit Apple to enforcement via binary scanning. Developer responsibility is the operative phrase.

    What are the AWS credential types and which ones leak?

    AWS issues several credential types, each with a distinct prefix and risk profile:

    PrefixCredential typeLifetimeWhere it belongs
    AKIAIAM user long-lived access keyForever (until rotated)Server environments only, ideally never
    ASIAAWS STS short-lived session token15 minutes to 36 hoursServer, or scoped to a per-user mobile session
    AROAIAM role unique identifierIdentifier only, not a credentialLogs and audit records
    AIDAIAM user unique identifierIdentifier onlyLogs and audit records
    AGPAIAM group identifierIdentifier onlyLogs and audit records
    (no prefix)Root account access keyForeverNowhere; AWS recommends never creating these

    The AKIA and root account keys are the dangerous ones for mobile apps. They grant unrestricted access (root) or whatever the IAM user's policy allows (AKIA), and they have no expiry. A strings extraction from an IPA that finds either is an emergency.

    ASIA tokens are short-lived, which limits the damage from a single extraction. They are still not appropriate for embedding in a binary; the correct pattern is per-user STS credentials issued at session start, not baked into the build.

    How easy is it for an attacker to find them?

    A decrypted IPA is a ZIP archive. Four shell commands on any Mac or Linux machine extract the binary, run strings against it, and grep for every AWS credential pattern:

    unzip MyApp.ipa
    cd Payload/MyApp.app
    strings MyApp | grep -E 'AKIA[0-9A-Z]{16}|ASIA[0-9A-Z]{16}|aws_secret_access_key'
    find Frameworks -name '*.dylib' -exec strings {} \; | grep -E 'AKIA|ASIA'
    

    The regex matches IAM access key IDs (20 characters total, AKIA prefix plus 16 alphanumeric) and session tokens (same shape with ASIA). The fourth line catches credentials embedded inside third-party frameworks the app bundles. The Spaceraccoon writeup on hunting credentials in iOS apps documents that this workflow finds AWS keys regularly in production App Store apps.

    Obfuscation does not change the outcome. A key XOR'd against a constant, base64-encoded, or split across multiple strings still has to be reassembled at runtime. A dynamic instrumentation tool like Frida intercepts the AWS SDK's setCredentials call and reads the decoded value out of memory the moment the app uses it.

    What is the correct architecture for AWS access from an iOS app?

    Two patterns, depending on whether the app already uses an identity provider:

    Pattern A: Cognito Identity Pool. The iOS client authenticates the user (Cognito User Pool, Apple Sign In, Google Sign In, custom backend). Cognito Identity Pool exchanges the user's identity token for short-lived AWS credentials scoped to an IAM role. The role's policy bounds what the user can do in AWS. No long-lived credentials touch the device.

    Pattern B: AWS STS AssumeRoleWithWebIdentity. The iOS client signs into your existing identity provider (Supabase Auth, Auth0, Firebase Auth) and receives a JWT. The client calls STS.AssumeRoleWithWebIdentity with the JWT. STS exchanges the JWT for short-lived AWS credentials scoped to a trust-policy-defined role. The role policy bounds the per-user access.

    Both patterns share the underlying principle: long-lived credentials live in IAM (your control plane), short-lived credentials reach the device, IAM policy bounds the damage if the short-lived credentials are stolen. The differences are operational: Cognito Identity Pool is the integrated AWS path; AssumeRoleWithWebIdentity works with any OIDC-compliant identity provider.

    For backend operations that the app legitimately cannot perform (cross-user data processing, billing operations), the request flows through your own backend, which uses its own long-lived IAM credentials never seen by the client.

    What does an IAM least-privilege policy look like in practice?

    The IAM policy attached to the role assumed by the client should grant exactly the permissions a user needs and nothing more. For an app that uploads files to a per-user folder in S3, the policy looks like:

    {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Action": ["s3:PutObject", "s3:GetObject"],
        "Resource": "arn:aws:s3:::my-bucket/${cognito-identity.amazonaws.com:sub}/*"
      }]
    }
    

    The ${cognito-identity.amazonaws.com:sub} placeholder is filled in with the authenticated user's identity ID at request time. The policy authorises read and write only against objects under the user's own prefix, which means a stolen session token can only access that user's files, not the rest of the bucket.

    For PTKD.com (https://ptkd.com) audits on AWS-backed iOS apps, IAM policy review is the second-pass check after the credential scan. A scoped policy with Resource set to * is functionally equivalent to root access for the scope of that role; the role pattern needs to mirror the data model.

    What to watch out for

    Three details that recur in audits.

    First, AWS credentials hide in .plist files and embedded frameworks, not just the main executable. The strings check has to run against every Mach-O in the bundle and every plist file in the resources. A credential cleanup that only addresses the main executable misses the most common hiding spot.

    Second, the AWS Mobile SDK's awsconfiguration.json is sometimes shipped in the bundle with credentials inline. The Cognito Identity Pool configuration is meant to live there, which is fine; an IAM access key embedded as CognitoCredentialsProvider.CredentialsProvider.Credentials.AccessKey is not. Check the JSON content, not just the file's presence.

    Third, the IAM policy is the second attack surface even when credentials are issued correctly. A role with Action: "*" or Resource: "*" lets an attacker who steals a short-lived token do as much damage as if they had the IAM user's long-lived key. The damage bound is the policy, not the credential lifetime.

    Key takeaways

    • Apple App Review does not scan for AWS credentials of any type. The strings command an attacker would run takes you ten seconds.
    • AKIA and root account keys are the high-severity finds. ASIA tokens are still wrong but limited by lifetime.
    • The architectural answer is Cognito Identity Pools or AWS STS AssumeRoleWithWebIdentity, with IAM policies scoped to per-user resources.
    • For mobile apps that bundle the AWS SDK, PTKD.com (https://ptkd.com) scans the IPA for every AWS prefix and maps each finding to OWASP MASVS controls.
    • Document the credential audit and the IAM policy review in your CHANGELOG so the next AI-generated change does not silently reintroduce a long-lived key.
    • #app-store
    • #aws
    • #iam
    • #ios
    • #ipa
    • #credentials

    Frequently asked questions

    What is the difference between AKIA and ASIA prefixes in AWS keys?
    AKIA is the prefix for long-lived IAM user access keys; ASIA is the prefix for short-lived session tokens issued by AWS STS. Both are dangerous in a mobile binary, but AKIA keys are the worse failure mode because they have no expiry. ASIA tokens expire (typically 15 minutes to 36 hours), which limits the window for an attacker who extracts them but does not eliminate the exposure.
    Are AWS root account keys different from IAM keys?
    Yes, and dangerously so. Root account access keys grant unrestricted access to the entire AWS account, including billing and IAM. AWS explicitly recommends never creating root access keys at all and deleting any that exist. A root key in an iOS app is the worst possible exposure: the attacker can lock you out of your own account.
    Does the AWS Mobile SDK help with this?
    The AWS Mobile SDK supports the Cognito Identity Pool pattern, which exchanges a user authentication token for short-lived AWS credentials scoped by IAM role. Using the SDK correctly means there are no long-lived credentials in the binary. The SDK does not prevent the developer from pasting an IAM key into the configuration, which is the failure mode this article covers.
    Will Apple flag the AWS Mobile SDK itself?
    No. The AWS Mobile SDK is a legitimate framework with a published Privacy Manifest. Apple review accepts apps that bundle it. The credential exposure happens inside the developer's code, not the SDK's, and Apple's review does not look there.
    How do I scan my IPA for AWS credential patterns?
    Run 'strings' against the compiled binary and grep for the AKIA, ASIA, and aws_secret_access_key patterns. A four-line shell pipeline against an unzipped IPA finds 95% of cases. The remaining 5% live in embedded frameworks or in plist files; extending the scan to those covers it. Third-party scanners run the same patterns plus several dozen others automatically.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free