用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill swift-auth-security-audit-suite命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | swift-auth-security-audit-suite |
| description | >- Use when this capability is needed. |
A functional auth flow can still leak secrets, enumerate users, or race itself into a corrupt token state. This skill builds a security-audit test suite that exercises the auth subsystem the way an attacker would: it scans for stored-secret leaks, validates App Transport Security, throws hostile inputs at validators, proves the error mapper can't be used for user enumeration, and asserts the concurrency and install-hygiene invariants. It is provider-agnostic — the anti-enumeration rule holds for Cognito, Firebase, Auth0, Okta, or any OAuth/OIDC backend.
UserDefaults key, a pasteboard
copy) and you want a regression-locking test.state is single-use and compared in
constant time, and that the provider's error codes never reach the UI.Announce on invoke: "Using swift-auth-security-audit-suite to add attacker-perspective auth tests (leakage, ATS, anti-enumeration, OAuth state) per OWASP MASVS-AUTH + RFC 9700."
Do not treat this suite as a substitute for server-side controls. Client tests are
defense-in-depth; the provider must also be configured to suppress user-existence errors
(e.g. Cognito PreventUserExistenceErrors=ENABLED). Both layers are required.
| Audit area | Assertion | Source |
|---|---|---|
| Token leakage — storage | No UserDefaults key whose name/value looks token-like; tokens live only in Keychain | OWASP MASVS-STORAGE |
| Token leakage — pasteboard | UIPasteboard.general.string doesn't echo a secret after a copy event | MASVS-STORAGE |
| Token leakage — logs | No os_log call interpolates a token as %{public}@; default %@ is .private | OSLogPrivacy |
| ATS | NSAllowsArbitraryLoads / …InWebContent not true; no TLS-min below TLSv1.2 without a justified NSExceptionDomains entry | MASTG-KNOW-0071 |
| Injection / boundary | Username/redirect validators reject javascript: schemes, NUL bytes, U+202E RTL override, over-length input | MASVS-CODE |
| Anti-enumeration | The error mapper never surfaces USER_NOT_FOUND / auth/user-not-found / "does not exist"; collapses to one generic credential error | provider docs (generalized) |
OAuth state CSRF | Two parallel flows produce different state; a tampered state on callback is rejected; comparison is constant-time | RFC 9700 / RFC 6749 §10.12 |
| Concurrent refresh | N parallel accessToken() calls → exactly one network refresh, all callers get the same token | MASVS-AUTH |
| First-launch hygiene | Fresh install (missing UserDefaults sentinel) purges stale Keychain items; idempotent across launches | Apple Keychain (survives uninstall) |
Every provider has a distinguishing "no such user" signal: Cognito UserNotFoundException, Firebase
auth/user-not-found, Auth0 invalid_grant with a user-not-found description. The UI must receive
one generic case ("Incorrect username or password"). The test iterates the data-layer error enum
and asserts no case's user-facing message contains "not found", "does not exist", "unknown user",
or a raw provider code. (The server must also suppress these — e.g. Cognito PreventUserExistenceErrors=ENABLED.)
state is required even with PKCE — and compared in constant timeRFC 9700 lets PKCE provide CSRF protection only when the authorization server supports it; otherwise
state is required. Best practice: always send both. The audit asserts (a) state differs across
parallel flows, (b) a tampered callback state is rejected, (c) comparison uses
HMAC.isValidAuthenticationCode or XOR-accumulate — never == on the raw value.
Issue.record for sweep findings; #expect for hard invariantsFor "scan everything and report all leaks" passes (UserDefaults dump, log grep), use
Issue.record(...) so one offending key doesn't abort the sweep. For binary invariants (ATS has no
arbitrary loads; refresh is single-flight) use #expect.
iOS keeps Keychain items across app uninstall by design. Test that a missing first-launch sentinel triggers a purge, and that running the hook twice leaves the same state (no crash, no double-delete error).
import Testing
import Foundation
@testable import MyApp // @testable import last
@Suite("Auth security audit")
struct AuthSecurityAuditTests {
@Test func noTokenLikeKeysInUserDefaults() {
for (key, value) in UserDefaults.standard.dictionaryRepresentation()
where key.lowercased().contains("token") || key.lowercased().contains("secret") {
Issue.record("Secret-like UserDefaults key leaked: \(key) = \(value)") // soft: report all
}
}
@Test func atsHasNoArbitraryLoads() {
let ats = Bundle.main.object(forInfoDictionaryKey: "NSAppTransportSecurity") as? [String: Any] ?? [:]
#expect(ats["NSAllowsArbitraryLoads"] as? Bool != true)
#expect(ats["NSAllowsArbitraryLoadsInWebContent"] as? Bool != true)
}
@Test(arguments: ["javascript:alert(1)", "user\u{0000}name", , (repeating: , count: )])
( : ) {
#expect(.isValid(input) )
}
() {
mapped .allCasesForTesting.map(.message(for:)) {
m mapped.lowercased()
#expect(m.contains())
#expect(m.contains())
#expect(m.contains())
}
}
() {
a .generate(), b .generate()
#expect(a.value b.value)
#expect(a.matches(a.value))
#expect(a.matches(b.value))
}
() {
session ()
withTaskGroup(of: ?.) { group
{ group.addTask { session.accessToken() } }
tokens: [] []
t group { t { tokens.append(t) } }
#expect((tokens).count )
#expect(session.refreshCallCount )
}
}
() {
.reset()
.purgeStaleKeychainIfNeeded()
.purgeStaleKeychainIfNeeded()
#expect(.didComplete)
}
}
UIPasteboard check is enough for logic; only escalate
to an XCUIApplication keyboard-driven test if a real copy button is the surface under audit.global-skills/apple-auth/swift-auth-security-checklist/SKILL.md — the defense-in-depth checklist
these tests verify.global-skills/apple-auth/swift-post-quantum-security-ios26/SKILL.md — the constant-time comparison
the state tests rely on (HMAC.isValidAuthenticationCode).global-skills/apple-auth/swift-testing-framework-conventions-mvvm/SKILL.md — Swift Testing
conventions (@Suite, import order, Issue.record vs #expect).Last verified: 2026-06-03 against OWASP MASVS-AUTH / MASTG, OSLogPrivacy, Cognito
PreventUserExistenceErrors (exact name + ENABLED/LEGACY behavior confirmed), and RFC 9700.
The anti-enumeration rule was verified to generalize across Cognito/Firebase/Auth0.
Re-check after: WWDC26 + any CryptoKit/Security release, or by 2026-12-01. Decay risk: low
(RFC/OWASP-grounded; the testing API surface is stable).
Found a drift? Run /skill-pattern-freshness-audit apple-auth.
Source: esaldgut/ai-native-engineering-workspace — distributed by TomeVault.