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.
AKIAfor IAM access keys,ASIAfor STS session tokens,aws_secret_access_keyfor 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:
| Prefix | Credential type | Lifetime | Where it belongs |
|---|---|---|---|
AKIA | IAM user long-lived access key | Forever (until rotated) | Server environments only, ideally never |
ASIA | AWS STS short-lived session token | 15 minutes to 36 hours | Server, or scoped to a per-user mobile session |
AROA | IAM role unique identifier | Identifier only, not a credential | Logs and audit records |
AIDA | IAM user unique identifier | Identifier only | Logs and audit records |
AGPA | IAM group identifier | Identifier only | Logs and audit records |
| (no prefix) | Root account access key | Forever | Nowhere; 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.




