Lab 9.3 — Security Audit
Goal: Perform a complete internal security audit on a deliberately vulnerable iOS app — find 8 OWASP Mobile Top 10 violations, categorize them by M-number, and produce a prioritized remediation plan.
Time: ~4 hours
Prerequisites:
- All of Phase 9
mitmproxy,objection,MobSF(Docker is easiest),semgrep- A jailbroken test device OR the iOS simulator (lab works mostly on simulator; jailbreak-specific findings are documented but not directly exploitable)
Setup
git clone https://github.com/bl9/swift-engineer-labs.git
cd swift-engineer-labs/09-security/security-audit/starter
open VulnerableBankApp.xcodeproj
The starter is a fake “banking” app — login, balance, transfers. It contains 8 deliberate OWASP violations. Your job is to find them all by category, fix each with the correct primitive, and write the audit report.
Tasks
Task 1 — Static analysis
Run static analysis tools and triage findings:
# semgrep
semgrep --config "p/swift" --config "p/security-audit" VulnerableBankApp/
# Note any high-confidence findings.
# strings scan
strings build/Release-iphonesimulator/VulnerableBankApp.app/VulnerableBankApp \
| grep -iE "(api_key|password|secret|token|sk_live|http://)"
# MobSF (Docker)
docker run -it --rm -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest
# Upload the .ipa via http://localhost:8000
Record every finding in audit-report.md with file:line references.
Task 2 — Dynamic analysis
# mitmproxy on port 8080, install CA on simulator
mitmproxy --listen-port 8080
In simulator: System Settings → Network → set HTTP Proxy to 127.0.0.1:8080; install the mitmproxy CA per Lab 9.2.
Run the app, log in, view balance, attempt a transfer. Inspect every request in mitmproxy.
Then run objection (requires Frida-injectable build — provided Debug-Frida config in the starter):
objection --gadget "VulnerableBankApp" explore
# Inside REPL:
ios keychain dump
ios nsuserdefaults get
ios cookies get
memory list modules
Task 3 — Find the 8 violations
Without spoiling: each violation maps to a specific M-category. They cover roughly: credential storage, authentication, network communication, input validation, privacy, cryptography, binary protections, security misconfiguration. Use the OWASP Mobile Top 10 mapping from 9.1 as your scoring rubric.
For each finding, document:
- File / line reference
- M-category and brief description
- Severity (Critical / High / Medium / Low) per the rubric in 9.10
- Reproduction steps (concrete: “log in, observe X in mitmproxy”)
- Recommended fix with the correct iOS primitive
- Estimated effort (S/M/L)
Task 4 — Apply the fixes
In the fixed/ directory, implement each remediation:
- Move secrets from
UserDefaultsto Keychain with appropriate accessibility - Replace plain HTTP with HTTPS + pinning
- Sanitize NSPredicate format strings with
%@placeholders - Remove hardcoded API keys; replace with a server-issued short-lived token
- Add the missing
PrivacyInfo.xcprivacyand accurate nutrition-label declarations - Replace ECB-mode CommonCrypto with
AES.GCMfrom CryptoKit - Strip Swift symbols in release; add the missing build-script audit
- Fix the
os_log%{public}@token leak - Upgrade weak Keychain accessibility (
AccessibleAlways→AccessibleAfterFirstUnlockThisDeviceOnlyat minimum)
After each fix, re-run the relevant static/dynamic check to verify the finding is closed.
Task 5 — Write the audit report
Produce audit-report.md with:
- Executive summary — total findings by severity, key risk areas, headline conclusion
- Findings — one entry per violation with all fields above
- Remediation plan — prioritized by severity, with owners and estimated dates
- Verification matrix — table mapping each finding to the tool/test that confirmed the fix
- Residual risk — what’s still exposed even after all fixes (e.g., reverse engineering, server-side attacks)
This is what real security reports look like. Practice the format; you’ll see it again.
Task 6 — CI gates to prevent regressions
For each fix, add a CI check that fails the build if the regression recurs:
- SwiftLint custom rule for
UserDefaultssecret writes - semgrep ruleset committed and enforced
- Build script asserting no
NSAllowsArbitraryLoadsin release Info.plist - Build script asserting no
STRIP_SWIFT_SYMBOLS = NOin release xcconfig - Strings-based scan that fails on hardcoded
sk_live_orBearerliterals
Demonstrate each check failing on a deliberate regression, then passing once reverted.
Stretch goals
- App Attest integration — wire the transfer endpoint to require an attestation assertion. Use a mock server.
- Threat model document — beyond the findings, write a one-pager threat model: actors, motivations, attack surfaces, mitigations. The kind of document a security review asks for.
- Coordinated-disclosure simulation — pretend you found these in a third-party app. Draft the disclosure email with timeline.
- Comparison study — run MobSF against a real shipping app (your own past projects, or a non-production sample). Note what shipping apps actually look like under the same scanner.
Notes
- Don’t run mitmproxy or trust user-installed CAs on your personal device after the lab. Reset the CA trust in Settings.
- The lab uses fake data and a mock server. Don’t point any of these techniques at real banking apps without explicit authorization — that’s a CFAA violation in the US (and equivalents elsewhere).
- The “8 violations” count is intentional. If you find more, congratulations — note them in your report as bonus findings.
This concludes Phase 9. Continue to Phase 10 — Deployment & CI/CD.