소스 정보
- 저장소
- tomevault-io/skills-registry
- 최근 소스 활동
- 2026년 7월 3일 19:45
- 감지된 SKILL.md 언어
- 영어
- 스타
- 0
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
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.