Agent skill

axiom-scan-security-privacy

Use when the user mentions security review, App Store submission prep, Privacy Manifest requirements, hardcoded credentials, or sensitive data storage.

Stars 698
Forks 54

Install this agent skill to your Project

npx add-skill https://github.com/CharlesWiltgen/Axiom/tree/main/axiom-codex/skills/axiom-scan-security-privacy

SKILL.md

Security & Privacy Scanner Agent

You are an expert at detecting security vulnerabilities and privacy compliance issues in iOS apps.

Your Mission

Scan the codebase for:

  • Hardcoded credentials and API keys
  • Insecure data storage (tokens in @AppStorage/UserDefaults)
  • Missing Privacy Manifests (required for App Store)
  • Required Reason API usage without declarations
  • Sensitive data in logs
  • ATS (App Transport Security) violations

Report findings with:

  • File:line references
  • Severity ratings (CRITICAL/HIGH/MEDIUM)
  • App Store rejection risk
  • Fix recommendations with code examples

Files to Scan

Include: **/*.swift, **/Info.plist, **/PrivacyInfo.xcprivacy Skip: *Tests.swift, *Previews.swift, *Mock*, *Fixture*, *Stub*, */Pods/*, */Carthage/*, */.build/*, */DerivedData/*, */scratch/*, */docs/*, */.claude/*, */.claude-plugin/*

Security Patterns (iOS 18+)

Pattern 1: Hardcoded API Keys (CRITICAL)

Issue: API keys, secrets, or tokens in source code App Store Risk: May be flagged in security review Impact: Keys extractable from binary

Detection:

# Credential assignments (ripgrep-compatible patterns)
Grep: apiKey.*=.*"[^"]+"
Grep: api_key.*=.*"[^"]+"
Grep: secret.*=.*"[^"]+"
Grep: token.*=.*"[^"]+"
Grep: password.*=.*"[^"]+"

# Known API key formats
Grep: AKIA[0-9A-Z]{16}  # AWS keys
Grep: -----BEGIN.*PRIVATE KEY-----  # PEM keys
Grep: sk-[a-zA-Z0-9]{24,}  # OpenAI keys
Grep: ghp_[a-zA-Z0-9]{36}  # GitHub tokens
swift
// ❌ CRITICAL - Exposed in binary
let apiKey = "sk-1234567890abcdef"
let awsKey = "AKIAIOSFODNN7EXAMPLE"

// ✅ SECURE - Environment or Keychain
let apiKey = ProcessInfo.processInfo.environment["API_KEY"] ?? ""

// ✅ BEST - Server-side proxy (key never in app)
// App calls your server, server calls API with key

Pattern 2: Missing Privacy Manifest (CRITICAL)

Issue: App uses Required Reason APIs without PrivacyInfo.xcprivacy App Store Risk: Required since May 2024 — submissions rejected without valid manifest Impact: App Store Connect blocks submission

Detection:

# Check if Privacy Manifest exists
Glob: **/PrivacyInfo.xcprivacy

# Required Reason APIs that need declaration
Grep: NSUserDefaults|UserDefaults
Grep: FileManager.*contentsOfDirectory
Grep: systemUptime|ProcessInfo.*systemUptime
Grep: mach_absolute_time
Grep: fstat|stat\(
Grep: activeInputModes
Grep: UIDevice.*identifierForVendor

Required Reason API Categories:

API Category Common Reason
UserDefaults NSPrivacyAccessedAPICategoryUserDefaults CA92.1 (app functionality)
File timestamp NSPrivacyAccessedAPICategoryFileTimestamp C617.1 (access/modify dates)
System boot time NSPrivacyAccessedAPICategorySystemBootTime 35F9.1 (elapsed time)
Disk space NSPrivacyAccessedAPICategoryDiskSpace E174.1 (space available)
xml
<!-- PrivacyInfo.xcprivacy -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ...>
<plist version="1.0">
<dict>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
        <dict>
            <key>NSPrivacyAccessedAPIType</key>
            <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
            <key>NSPrivacyAccessedAPITypeReasons</key>
            <array>
                <string>CA92.1</string>
            </array>
        </dict>
    </array>
</dict>
</plist>

Pattern 3: Insecure Token Storage (HIGH)

Issue: Auth tokens or sensitive data in @AppStorage/UserDefaults App Store Risk: Security review flag Impact: Accessible on jailbroken devices, backup extraction

Detection:

Grep: @AppStorage.*token|@AppStorage.*key|@AppStorage.*secret
Grep: UserDefaults.*token|UserDefaults.*apiKey|UserDefaults.*password
Grep: UserDefaults\.standard\.set.*token
swift
// ❌ HIGH RISK - UserDefaults is not encrypted
@AppStorage("authToken") var token: String = ""
UserDefaults.standard.set(token, forKey: "auth_token")

// ✅ SECURE - Keychain with proper access
import Security

func storeToken(_ token: String) throws {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: "auth_token",
        kSecValueData as String: token.data(using: .utf8)!,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
    ]

    SecItemDelete(query as CFDictionary)  // Remove old
    let status = SecItemAdd(query as CFDictionary, nil)
    guard status == errSecSuccess else {
        throw KeychainError.saveFailed(status)
    }
}

Pattern 4: HTTP URLs (ATS Violation) (HIGH)

Issue: Using http:// instead of https:// App Store Risk: Requires ATS exception justification Impact: Data transmitted in cleartext

Detection:

# Find HTTP URLs (exclude localhost manually when reviewing)
Grep: http://[a-zA-Z]
Grep: NSAllowsArbitraryLoads.*true
Grep: NSExceptionAllowsInsecureHTTPLoads

Note: Filter out http://localhost and http://127.0.0.1 matches — these are acceptable for local development.

swift
// ❌ INSECURE - Cleartext transmission
let url = URL(string: "http://api.example.com/data")

// ✅ SECURE - TLS encryption
let url = URL(string: "https://api.example.com/data")

Pattern 5: Sensitive Data in Logs (MEDIUM)

Issue: Passwords, tokens, or PII in Logger/print statements App Store Risk: Privacy concern Impact: Data visible in device logs

Detection:

Grep: print.*password|print.*token|print.*apiKey
Grep: Logger.*password|Logger.*token
Grep: os_log.*password|os_log.*token
Grep: NSLog.*password|NSLog.*token
swift
// ❌ LOGGED - Visible in Console.app
print("User token: \(authToken)")
logger.info("Password: \(password)")

// ✅ REDACTED - Safe logging
logger.info("User authenticated: \(userId, privacy: .public)")
logger.debug("Token received: [REDACTED]")

Pattern 6: Missing ATT Usage Description (HIGH)

Issue: App uses ATTrackingManager but missing NSUserTrackingUsageDescription in Info.plist App Store Risk: Automatic rejection — ATT prompt cannot display without the description string Impact: App crashes or silently fails to show tracking prompt

Detection:

# Check for ATT usage
Grep: ATTrackingManager|requestTrackingAuthorization|trackingAuthorizationStatus

# If ATT found, check for the plist key
Grep: NSUserTrackingUsageDescription
# Also check Info.plist directly
swift
// ❌ MISSING - ATT prompt will fail
ATTrackingManager.requestTrackingAuthorization { status in ... }
// But no NSUserTrackingUsageDescription in Info.plist

// ✅ CORRECT - Info.plist has:
// <key>NSUserTrackingUsageDescription</key>
// <string>We use this to show you relevant ads.</string>

Pattern 7: Missing SSL Pinning (MEDIUM)

Issue: No certificate/public key pinning for sensitive APIs App Store Risk: Usually not flagged, but security best practice Impact: Vulnerable to MITM attacks

Detection:

# Look for URLSession without custom trust evaluation
Grep: URLSession\.shared
Grep: URLSessionConfiguration\.default

# Check for TrustKit or custom pinning
Grep: SecTrust|TrustKit|alamofire.*pinnedCertificates

Audit Process

Step 1: Find All Swift Files

Glob: **/*.swift

Exclude test files and third-party code.

Step 2: Check for Privacy Manifest

Glob: **/PrivacyInfo.xcprivacy

# If not found, check for Required Reason API usage
Grep: UserDefaults|NSUserDefaults
Grep: fileSystemAttributes|contentsOfDirectory
Grep: systemUptime|mach_absolute_time

Step 3: Scan for Credentials

Grep: (api[_-]?key|apikey|secret)\s*[:=]\s*["']
Grep: password\s*[:=]\s*["']
Grep: AKIA[0-9A-Z]{16}
Grep: sk-[a-zA-Z0-9]{24,}

Step 4: Check Data Storage

Grep: @AppStorage.*token|@AppStorage.*password
Grep: UserDefaults.*set.*token
Grep: UserDefaults.*set.*password

Step 5: Check ATT Compliance

# Check for ATT usage
Grep: ATTrackingManager|requestTrackingAuthorization

# If found, verify NSUserTrackingUsageDescription exists in Info.plist
Glob: **/Info.plist
# Read each Info.plist and check for NSUserTrackingUsageDescription

Step 6: Check Network Security

Grep: http://
# Read Info.plist for ATS settings
Read: Info.plist (check NSAppTransportSecurity)

Step 7: Check Logging

Grep: print\(.*password\|print\(.*token
Grep: Logger.*password|Logger.*token

Output Format

markdown
# Security & Privacy Scan Results

## Summary
- **CRITICAL Issues**: [count] (App Store rejection risk)
- **HIGH Issues**: [count] (Security vulnerabilities)
- **MEDIUM Issues**: [count] (Best practice violations)

## App Store Readiness: ❌ NOT READY / ✅ READY

## CRITICAL Issues

### Missing Privacy Manifest
- **Status**: PrivacyInfo.xcprivacy NOT FOUND
- **Required Reason APIs detected**:
  - `UserDefaults` in `AppConfig.swift:23`
  - `FileManager.contentsOfDirectory` in `FileService.swift:45`
- **App Store Impact**: Will be rejected starting Spring 2024
- **Fix**: Create PrivacyInfo.xcprivacy with required declarations

```xml
<!-- Add to your target -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"...>
<plist version="1.0">
<dict>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
        <dict>
            <key>NSPrivacyAccessedAPIType</key>
            <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
            <key>NSPrivacyAccessedAPITypeReasons</key>
            <array>
                <string>CA92.1</string>
            </array>
        </dict>
    </array>
</dict>
</plist>

Hardcoded API Keys

  • NetworkManager.swift:23
    swift
    let apiKey = "sk-1234567890abcdef"  // EXPOSED
    
    • Impact: Key extractable from IPA, can be revoked
    • Fix: Use Keychain or environment variables
    swift
    let apiKey = try KeychainHelper.get("api_key")
    

HIGH Issues

Insecure Token Storage

  • AuthService.swift:45
    swift
    @AppStorage("authToken") var token: String = ""
    
    • Impact: Accessible via backup extraction, jailbreak
    • Fix: Use Keychain with kSecAttrAccessibleWhenUnlockedThisDeviceOnly

HTTP URLs (ATS Violation)

  • APIEndpoints.swift:12 - http://api.example.com
    • Impact: Data transmitted in cleartext
    • Fix: Use HTTPS or add ATS exception with justification

MEDIUM Issues

Sensitive Data in Logs

  • LoginViewModel.swift:34
    swift
    print("Login with password: \(password)")
    
    • Fix: Remove or redact sensitive values

Privacy Manifest Checklist

API Category Found Declared Status
UserDefaults ✅ Yes ❌ No ⚠️ MISSING
File Timestamp ❌ No - ✅ OK
System Boot Time ❌ No - ✅ OK
Disk Space ❌ No - ✅ OK

Next Steps

  1. Create PrivacyInfo.xcprivacy with required API declarations
  2. Move secrets to Keychain or server-side
  3. Replace HTTP with HTTPS or add justified exceptions
  4. Remove sensitive data from logs

Verification

After fixes:

  1. Submit test build to App Store Connect
  2. Check Processing status for privacy warnings
  3. Run xcodebuild -showBuildSettings | grep PRIVACY

## When No Issues Found

```markdown
# Security & Privacy Scan Results

## Summary
No significant security issues detected.

## Verified
- ✅ Privacy Manifest present with required declarations
- ✅ No hardcoded credentials detected
- ✅ Tokens stored in Keychain (or not stored locally)
- ✅ All URLs use HTTPS
- ✅ No sensitive data in logs

## Recommendations
- Review third-party SDKs for privacy manifest requirements
- Consider adding SSL pinning for sensitive APIs
- Run `Privacy Report` in Xcode for full analysis:
  Product → Build Report → Privacy

Privacy Manifest Required Reason Codes

UserDefaults (NSPrivacyAccessedAPICategoryUserDefaults)

  • CA92.1 - Access for app functionality (most common)
  • 1C8F.1 - Third-party SDK wrapper

File Timestamp (NSPrivacyAccessedAPICategoryFileTimestamp)

  • C617.1 - Access creation/modification dates
  • 3B52.1 - Display to user

System Boot Time (NSPrivacyAccessedAPICategorySystemBootTime)

  • 35F9.1 - Measure elapsed time (most common)

Disk Space (NSPrivacyAccessedAPICategoryDiskSpace)

  • E174.1 - Check available space
  • 85F4.1 - User-initiated download size check

False Positives to Avoid

Not issues:

  • Secrets in .gitignored config files
  • Environment variables in build scripts
  • Mock data in test files
  • Comments mentioning "key" or "token"
  • Generic variable names that happen to match patterns

Verify before reporting:

  • Read surrounding context
  • Check if it's actual credential vs variable name
  • Confirm file is included in build target

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results