attackmap-analyzer-swift 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- attackmap_analyzer_swift-0.2.0/LICENSE +21 -0
- attackmap_analyzer_swift-0.2.0/PKG-INFO +175 -0
- attackmap_analyzer_swift-0.2.0/README.md +136 -0
- attackmap_analyzer_swift-0.2.0/pyproject.toml +76 -0
- attackmap_analyzer_swift-0.2.0/setup.cfg +4 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift/__init__.py +4 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift/analyzer.py +296 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift/apple_surface.py +765 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift/objc.py +545 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift/routes.py +1195 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift/sbom.py +58 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift/swiftsrc.py +239 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift.egg-info/PKG-INFO +175 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift.egg-info/SOURCES.txt +20 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift.egg-info/dependency_links.txt +1 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift.egg-info/entry_points.txt +3 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift.egg-info/requires.txt +9 -0
- attackmap_analyzer_swift-0.2.0/src/attackmap_analyzer_swift.egg-info/top_level.txt +1 -0
- attackmap_analyzer_swift-0.2.0/tests/test_apple_surface.py +380 -0
- attackmap_analyzer_swift-0.2.0/tests/test_objc.py +244 -0
- attackmap_analyzer_swift-0.2.0/tests/test_routes.py +641 -0
- attackmap_analyzer_swift-0.2.0/tests/test_swift_analyzer.py +231 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matthew Davis and AttackMap Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: attackmap-analyzer-swift
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Swift ecosystem analyzer plugin for AttackMap: Vapor/Hummingbird routes with route-level auth, the iOS/macOS app attack surface, and a SwiftPM/CocoaPods/Carthage SBOM.
|
|
5
|
+
Author: AttackMap Contributors
|
|
6
|
+
Author-email: Matthew Davis <mlaify@mlaify.io>
|
|
7
|
+
Maintainer-email: Matthew Davis <mlaify@mlaify.io>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/mlaify/attackmap-analyzer-swift
|
|
10
|
+
Project-URL: Repository, https://github.com/mlaify/attackmap-analyzer-swift
|
|
11
|
+
Project-URL: Issues, https://github.com/mlaify/attackmap-analyzer-swift/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/mlaify/attackmap-analyzer-swift/blob/main/CHANGELOG.md
|
|
13
|
+
Project-URL: AttackMap core, https://github.com/mlaify/AttackMap
|
|
14
|
+
Keywords: security,static-analysis,appsec,defensive-security,attackmap,attackmap-plugin,swift
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Information Technology
|
|
18
|
+
Classifier: Intended Audience :: System Administrators
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
|
+
Classifier: Topic :: Security
|
|
26
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: pydantic>=2.7.0
|
|
32
|
+
Provides-Extra: core
|
|
33
|
+
Requires-Dist: attackmap>=0.6.0; extra == "core"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
37
|
+
Requires-Dist: attackmap>=0.6.0; extra == "dev"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# attackmap-analyzer-swift
|
|
41
|
+
|
|
42
|
+
> [!IMPORTANT]
|
|
43
|
+
> **Active development, slow pace.** AttackMap is under active development, but
|
|
44
|
+
> progress may be slow until more contributors or co-maintainers join. Help is
|
|
45
|
+
> very welcome with the core engine, an analyzer, the macOS app, or the docs —
|
|
46
|
+
> see [CONTRIBUTING.md](CONTRIBUTING.md) or open an issue on
|
|
47
|
+
> [mlaify/AttackMap](https://github.com/mlaify/AttackMap/issues) to say hello.
|
|
48
|
+
> Security reports are still welcome at [security@mlaify.io](mailto:security@mlaify.io).
|
|
49
|
+
|
|
50
|
+
Swift ecosystem analyzer plugin for [AttackMap](https://github.com/mlaify/AttackMap).
|
|
51
|
+
Auto-discovered via the `attackmap.analyzers` entry point once installed.
|
|
52
|
+
|
|
53
|
+
[](LICENSE)
|
|
54
|
+
|
|
55
|
+
> **Status: experimental.** Vapor / Hummingbird routes with route-level auth, the
|
|
56
|
+
> iOS/macOS app attack surface, and a SwiftPM + CocoaPods + Carthage dependency SBOM.
|
|
57
|
+
> Requires an AttackMap core with the app-surface contract (mlaify/AttackMap#347).
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv tool install attackmap --with attackmap-analyzer-swift \
|
|
63
|
+
--index mlaify=https://pkg.mlaify.io/pypi/simple/ --index-strategy first-index
|
|
64
|
+
# or from source:
|
|
65
|
+
pip install git+https://github.com/mlaify/attackmap-analyzer-swift.git # alongside attackmap
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The analyzer is **experimental and opt-in** (`enabled_by_default=False`): installing
|
|
69
|
+
it does not make it run on every scan. Select it explicitly:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
attackmap analyze /path/to/swift/project -m swift
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Files are walked with `attackmap.sdk.iter_repo_files`: `.build/`, `DerivedData/`,
|
|
76
|
+
`Pods/`, `Carthage/` and AttackMap's shared skip list (`build/`, `.git/`,
|
|
77
|
+
`node_modules/`, ...) are pruned by their name *inside* the repo, and symlinks out
|
|
78
|
+
of the repo are not followed.
|
|
79
|
+
|
|
80
|
+
## What it does today
|
|
81
|
+
|
|
82
|
+
- **SwiftPM detection** — recognizes `Package.swift`, `.xcodeproj` / `.xcworkspace`,
|
|
83
|
+
and `.swift` sources; emits a `SwiftPM` framework hint.
|
|
84
|
+
- **Server-side routes** ([AttackMap#187](https://github.com/mlaify/AttackMap/issues/187)) —
|
|
85
|
+
Vapor 4 and Hummingbird 1.x/2.x route registrations (`app.get("users", ":id")`,
|
|
86
|
+
`on(.POST, ...)`, `webSocket`/`ws`, `router.get("/x")`, chained
|
|
87
|
+
`group.get(use:).post(use:)`), with prefixes from `grouped(...)` / `group(...)`
|
|
88
|
+
(closures, bindings and chains), and from where a `RouteCollection` or controller
|
|
89
|
+
is mounted (`register(collection:)`, `addRoutes(to:)`, `addRoutes(_:atPath:)`) when
|
|
90
|
+
every mount in the same Swift package agrees. Each route carries `auth`, `guards`
|
|
91
|
+
and `guard_evidence` (AttackMap#256): `required` when Vapor's
|
|
92
|
+
`X.guardMiddleware()` / `X.redirectMiddleware(...)`, Hummingbird's
|
|
93
|
+
`IsAuthenticatedMiddleware` or an `*Authorization*Middleware` applies, or the
|
|
94
|
+
handler calls `req.auth.require(...)` / `context.requireIdentity()` or guards on
|
|
95
|
+
the caller's identity with a 401. An authenticator alone (`UserAuthenticator()`,
|
|
96
|
+
`SessionAuthenticator`) leaves the route `unknown`, since it only identifies callers
|
|
97
|
+
who send credentials. Role checks in the handler (`guard user.roles.contains(.admin)`)
|
|
98
|
+
are reported as guards. Paths the code computes (`SiteURL.faq.pathComponents`) are
|
|
99
|
+
kept as `$(SiteURL.faq)`, and an unknown mount as `$(TypeName)`. Test targets
|
|
100
|
+
(`Tests/`, `*Tests/`) are skipped.
|
|
101
|
+
- **iOS/macOS app attack surface** ([AttackMap#188](https://github.com/mlaify/AttackMap/issues/188)) —
|
|
102
|
+
reported as `AppSurfaceIssue`s, which core turns into `apple-*` findings with CWE/OWASP ids.
|
|
103
|
+
- `Info.plist` (XML or binary, read with `plistlib`, never executed): App Transport
|
|
104
|
+
Security exceptions, i.e. `NSAllowsArbitraryLoads` (medium; low when a scoped key makes
|
|
105
|
+
iOS 10+ ignore it), `...InWebContent` / `...ForMedia`, and per-domain
|
|
106
|
+
`NSExceptionAllowsInsecureHTTPLoads` or a TLS minimum below 1.2 (low). Each custom
|
|
107
|
+
`CFBundleURLSchemes` scheme is an entry point and an `apple-custom-url-scheme` finding
|
|
108
|
+
(low); the handlers (`application(_:open:options:)`,
|
|
109
|
+
`scene(_:openURLContexts:)`, `.onOpenURL`) are reported as entry points.
|
|
110
|
+
- `*.entitlements`: `cs.disable-library-validation`, `allow-dyld-environment-variables`,
|
|
111
|
+
`allow-unsigned-executable-memory`, `disable-executable-page-protection` (medium);
|
|
112
|
+
`get-task-allow` outside a Debug/Dev entitlements file (low); `applinks:` universal-link
|
|
113
|
+
domains as entry points.
|
|
114
|
+
- `*.xcconfig`: secret-named build settings (`API_KEY`, `CLIENT_SECRET`, `AUTH_TOKEN`)
|
|
115
|
+
with a literal value (not `$(...)`, not a placeholder), reported as hard-coded secrets
|
|
116
|
+
with the value masked.
|
|
117
|
+
- Swift code:
|
|
118
|
+
- `evaluateJavaScript("...'\(value)'...")` where a value is interpolated *inside a JS
|
|
119
|
+
string literal* and isn't visibly encoded inline or where it was bound (`sanitized`,
|
|
120
|
+
`escaped`, `json`, ...). Medium when the value is named like input, else low.
|
|
121
|
+
- Secret-named values or keys written to `UserDefaults` (`set(_:forKey:)`,
|
|
122
|
+
`@AppStorage("authToken")`), or copied to `UIPasteboard.general`.
|
|
123
|
+
- `NSXPCListener` services (entry points), and a `shouldAcceptNewConnection` that
|
|
124
|
+
returns `true` without checking the peer: no audit token / PID / code-signing
|
|
125
|
+
requirement, no validate/verify helper, and the connection isn't passed to any call.
|
|
126
|
+
High when a `NSXPCListener(machServiceName:)` is registered in the same file or
|
|
127
|
+
target (top-level directory); otherwise low, since a bundled XPC service or anonymous
|
|
128
|
+
listener is reachable only by its parent app or an endpoint holder.
|
|
129
|
+
- `NSClassFromString` / `NSSelectorFromString` / `dlopen` on a string built at the
|
|
130
|
+
call site.
|
|
131
|
+
- URL-scheme and universal-link handlers as entry points.
|
|
132
|
+
- **Dependency SBOM** — parses `Package.resolved` (formats **v1**, **v2**, and **v3**,
|
|
133
|
+
including the copy Xcode stashes under `*.xcworkspace/xcshareddata/swiftpm/`) into
|
|
134
|
+
the scan's dependency inventory, marking direct vs. transitive by cross-referencing
|
|
135
|
+
the `Package.swift` manifest. SwiftPM pins carry their repository URL, which
|
|
136
|
+
`--cve` matches against OSV's `SwiftURL` ecosystem. CocoaPods `Podfile.lock` pods
|
|
137
|
+
are inventoried (`cocoapods`; direct when listed under `DEPENDENCIES:`, subspecs
|
|
138
|
+
folded into their pod); OSV has no CocoaPods database, so they aren't CVE-matched.
|
|
139
|
+
Carthage `Cartfile.resolved` pins are inventoried as `carthage` (direct when the
|
|
140
|
+
`Cartfile` lists them, a leading `v` dropped from tag versions) with the repository URL,
|
|
141
|
+
so `--cve` matches them against OSV's `SwiftURL` ecosystem like SwiftPM pins.
|
|
142
|
+
- **Framework hints** — flags server-side frameworks (Vapor, Hummingbird, Kitura,
|
|
143
|
+
Perfect) when declared in the manifest.
|
|
144
|
+
- **Entrypoints** — `main.swift` and `@main`.
|
|
145
|
+
|
|
146
|
+
- **Objective-C / Objective-C++** ([AttackMap#190](https://github.com/mlaify/AttackMap/issues/190)) —
|
|
147
|
+
a second analyzer in this package, `objc` (opt-in: `-m objc`), for `.m`/`.mm` files that
|
|
148
|
+
look like Objective-C (not MATLAB). It runs the same project-file checks (Info.plist,
|
|
149
|
+
entitlements, xcconfig, Cartfile.resolved) and, in code: URL-scheme / universal-link / XPC
|
|
150
|
+
entry points, `evaluateJavaScript:` with a `stringWithFormat:` `%@` inside a JS string
|
|
151
|
+
literal, secret-named values or keys in `NSUserDefaults` or on the pasteboard, XPC
|
|
152
|
+
listeners that return `YES` without checking the peer, `NSClassFromString` /
|
|
153
|
+
`NSSelectorFromString` / `dlopen` on built strings, and the native weaknesses shared with
|
|
154
|
+
the C/C++ plugins: a non-literal, non-localized format with no arguments
|
|
155
|
+
(`[NSString stringWithFormat:msg]`, `NSLog(msg)`) as `format_string`, and `/bin/sh -c`
|
|
156
|
+
with a built command or `system()`/`popen()` on a non-literal as `native_command_exec`.
|
|
157
|
+
`NSFileManager`/`NSURL` file sinks aren't reported (no Objective-C taint pass yet).
|
|
158
|
+
When both analyzers run, core's merge drops the duplicate project-file signals.
|
|
159
|
+
|
|
160
|
+
## Roadmap
|
|
161
|
+
|
|
162
|
+
- Taint for Swift/Objective-C sources (URL-scheme parameters to WKWebView / file sinks).
|
|
163
|
+
|
|
164
|
+
Part of the [Swift analyzer epic](https://github.com/mlaify/AttackMap/issues/204).
|
|
165
|
+
|
|
166
|
+
## Development
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
pip install -e ".[dev]"
|
|
170
|
+
pytest -q
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
[MIT](LICENSE). Copyright (c) 2026 Matthew Davis and AttackMap Contributors.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# attackmap-analyzer-swift
|
|
2
|
+
|
|
3
|
+
> [!IMPORTANT]
|
|
4
|
+
> **Active development, slow pace.** AttackMap is under active development, but
|
|
5
|
+
> progress may be slow until more contributors or co-maintainers join. Help is
|
|
6
|
+
> very welcome with the core engine, an analyzer, the macOS app, or the docs —
|
|
7
|
+
> see [CONTRIBUTING.md](CONTRIBUTING.md) or open an issue on
|
|
8
|
+
> [mlaify/AttackMap](https://github.com/mlaify/AttackMap/issues) to say hello.
|
|
9
|
+
> Security reports are still welcome at [security@mlaify.io](mailto:security@mlaify.io).
|
|
10
|
+
|
|
11
|
+
Swift ecosystem analyzer plugin for [AttackMap](https://github.com/mlaify/AttackMap).
|
|
12
|
+
Auto-discovered via the `attackmap.analyzers` entry point once installed.
|
|
13
|
+
|
|
14
|
+
[](LICENSE)
|
|
15
|
+
|
|
16
|
+
> **Status: experimental.** Vapor / Hummingbird routes with route-level auth, the
|
|
17
|
+
> iOS/macOS app attack surface, and a SwiftPM + CocoaPods + Carthage dependency SBOM.
|
|
18
|
+
> Requires an AttackMap core with the app-surface contract (mlaify/AttackMap#347).
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
uv tool install attackmap --with attackmap-analyzer-swift \
|
|
24
|
+
--index mlaify=https://pkg.mlaify.io/pypi/simple/ --index-strategy first-index
|
|
25
|
+
# or from source:
|
|
26
|
+
pip install git+https://github.com/mlaify/attackmap-analyzer-swift.git # alongside attackmap
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The analyzer is **experimental and opt-in** (`enabled_by_default=False`): installing
|
|
30
|
+
it does not make it run on every scan. Select it explicitly:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
attackmap analyze /path/to/swift/project -m swift
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Files are walked with `attackmap.sdk.iter_repo_files`: `.build/`, `DerivedData/`,
|
|
37
|
+
`Pods/`, `Carthage/` and AttackMap's shared skip list (`build/`, `.git/`,
|
|
38
|
+
`node_modules/`, ...) are pruned by their name *inside* the repo, and symlinks out
|
|
39
|
+
of the repo are not followed.
|
|
40
|
+
|
|
41
|
+
## What it does today
|
|
42
|
+
|
|
43
|
+
- **SwiftPM detection** — recognizes `Package.swift`, `.xcodeproj` / `.xcworkspace`,
|
|
44
|
+
and `.swift` sources; emits a `SwiftPM` framework hint.
|
|
45
|
+
- **Server-side routes** ([AttackMap#187](https://github.com/mlaify/AttackMap/issues/187)) —
|
|
46
|
+
Vapor 4 and Hummingbird 1.x/2.x route registrations (`app.get("users", ":id")`,
|
|
47
|
+
`on(.POST, ...)`, `webSocket`/`ws`, `router.get("/x")`, chained
|
|
48
|
+
`group.get(use:).post(use:)`), with prefixes from `grouped(...)` / `group(...)`
|
|
49
|
+
(closures, bindings and chains), and from where a `RouteCollection` or controller
|
|
50
|
+
is mounted (`register(collection:)`, `addRoutes(to:)`, `addRoutes(_:atPath:)`) when
|
|
51
|
+
every mount in the same Swift package agrees. Each route carries `auth`, `guards`
|
|
52
|
+
and `guard_evidence` (AttackMap#256): `required` when Vapor's
|
|
53
|
+
`X.guardMiddleware()` / `X.redirectMiddleware(...)`, Hummingbird's
|
|
54
|
+
`IsAuthenticatedMiddleware` or an `*Authorization*Middleware` applies, or the
|
|
55
|
+
handler calls `req.auth.require(...)` / `context.requireIdentity()` or guards on
|
|
56
|
+
the caller's identity with a 401. An authenticator alone (`UserAuthenticator()`,
|
|
57
|
+
`SessionAuthenticator`) leaves the route `unknown`, since it only identifies callers
|
|
58
|
+
who send credentials. Role checks in the handler (`guard user.roles.contains(.admin)`)
|
|
59
|
+
are reported as guards. Paths the code computes (`SiteURL.faq.pathComponents`) are
|
|
60
|
+
kept as `$(SiteURL.faq)`, and an unknown mount as `$(TypeName)`. Test targets
|
|
61
|
+
(`Tests/`, `*Tests/`) are skipped.
|
|
62
|
+
- **iOS/macOS app attack surface** ([AttackMap#188](https://github.com/mlaify/AttackMap/issues/188)) —
|
|
63
|
+
reported as `AppSurfaceIssue`s, which core turns into `apple-*` findings with CWE/OWASP ids.
|
|
64
|
+
- `Info.plist` (XML or binary, read with `plistlib`, never executed): App Transport
|
|
65
|
+
Security exceptions, i.e. `NSAllowsArbitraryLoads` (medium; low when a scoped key makes
|
|
66
|
+
iOS 10+ ignore it), `...InWebContent` / `...ForMedia`, and per-domain
|
|
67
|
+
`NSExceptionAllowsInsecureHTTPLoads` or a TLS minimum below 1.2 (low). Each custom
|
|
68
|
+
`CFBundleURLSchemes` scheme is an entry point and an `apple-custom-url-scheme` finding
|
|
69
|
+
(low); the handlers (`application(_:open:options:)`,
|
|
70
|
+
`scene(_:openURLContexts:)`, `.onOpenURL`) are reported as entry points.
|
|
71
|
+
- `*.entitlements`: `cs.disable-library-validation`, `allow-dyld-environment-variables`,
|
|
72
|
+
`allow-unsigned-executable-memory`, `disable-executable-page-protection` (medium);
|
|
73
|
+
`get-task-allow` outside a Debug/Dev entitlements file (low); `applinks:` universal-link
|
|
74
|
+
domains as entry points.
|
|
75
|
+
- `*.xcconfig`: secret-named build settings (`API_KEY`, `CLIENT_SECRET`, `AUTH_TOKEN`)
|
|
76
|
+
with a literal value (not `$(...)`, not a placeholder), reported as hard-coded secrets
|
|
77
|
+
with the value masked.
|
|
78
|
+
- Swift code:
|
|
79
|
+
- `evaluateJavaScript("...'\(value)'...")` where a value is interpolated *inside a JS
|
|
80
|
+
string literal* and isn't visibly encoded inline or where it was bound (`sanitized`,
|
|
81
|
+
`escaped`, `json`, ...). Medium when the value is named like input, else low.
|
|
82
|
+
- Secret-named values or keys written to `UserDefaults` (`set(_:forKey:)`,
|
|
83
|
+
`@AppStorage("authToken")`), or copied to `UIPasteboard.general`.
|
|
84
|
+
- `NSXPCListener` services (entry points), and a `shouldAcceptNewConnection` that
|
|
85
|
+
returns `true` without checking the peer: no audit token / PID / code-signing
|
|
86
|
+
requirement, no validate/verify helper, and the connection isn't passed to any call.
|
|
87
|
+
High when a `NSXPCListener(machServiceName:)` is registered in the same file or
|
|
88
|
+
target (top-level directory); otherwise low, since a bundled XPC service or anonymous
|
|
89
|
+
listener is reachable only by its parent app or an endpoint holder.
|
|
90
|
+
- `NSClassFromString` / `NSSelectorFromString` / `dlopen` on a string built at the
|
|
91
|
+
call site.
|
|
92
|
+
- URL-scheme and universal-link handlers as entry points.
|
|
93
|
+
- **Dependency SBOM** — parses `Package.resolved` (formats **v1**, **v2**, and **v3**,
|
|
94
|
+
including the copy Xcode stashes under `*.xcworkspace/xcshareddata/swiftpm/`) into
|
|
95
|
+
the scan's dependency inventory, marking direct vs. transitive by cross-referencing
|
|
96
|
+
the `Package.swift` manifest. SwiftPM pins carry their repository URL, which
|
|
97
|
+
`--cve` matches against OSV's `SwiftURL` ecosystem. CocoaPods `Podfile.lock` pods
|
|
98
|
+
are inventoried (`cocoapods`; direct when listed under `DEPENDENCIES:`, subspecs
|
|
99
|
+
folded into their pod); OSV has no CocoaPods database, so they aren't CVE-matched.
|
|
100
|
+
Carthage `Cartfile.resolved` pins are inventoried as `carthage` (direct when the
|
|
101
|
+
`Cartfile` lists them, a leading `v` dropped from tag versions) with the repository URL,
|
|
102
|
+
so `--cve` matches them against OSV's `SwiftURL` ecosystem like SwiftPM pins.
|
|
103
|
+
- **Framework hints** — flags server-side frameworks (Vapor, Hummingbird, Kitura,
|
|
104
|
+
Perfect) when declared in the manifest.
|
|
105
|
+
- **Entrypoints** — `main.swift` and `@main`.
|
|
106
|
+
|
|
107
|
+
- **Objective-C / Objective-C++** ([AttackMap#190](https://github.com/mlaify/AttackMap/issues/190)) —
|
|
108
|
+
a second analyzer in this package, `objc` (opt-in: `-m objc`), for `.m`/`.mm` files that
|
|
109
|
+
look like Objective-C (not MATLAB). It runs the same project-file checks (Info.plist,
|
|
110
|
+
entitlements, xcconfig, Cartfile.resolved) and, in code: URL-scheme / universal-link / XPC
|
|
111
|
+
entry points, `evaluateJavaScript:` with a `stringWithFormat:` `%@` inside a JS string
|
|
112
|
+
literal, secret-named values or keys in `NSUserDefaults` or on the pasteboard, XPC
|
|
113
|
+
listeners that return `YES` without checking the peer, `NSClassFromString` /
|
|
114
|
+
`NSSelectorFromString` / `dlopen` on built strings, and the native weaknesses shared with
|
|
115
|
+
the C/C++ plugins: a non-literal, non-localized format with no arguments
|
|
116
|
+
(`[NSString stringWithFormat:msg]`, `NSLog(msg)`) as `format_string`, and `/bin/sh -c`
|
|
117
|
+
with a built command or `system()`/`popen()` on a non-literal as `native_command_exec`.
|
|
118
|
+
`NSFileManager`/`NSURL` file sinks aren't reported (no Objective-C taint pass yet).
|
|
119
|
+
When both analyzers run, core's merge drops the duplicate project-file signals.
|
|
120
|
+
|
|
121
|
+
## Roadmap
|
|
122
|
+
|
|
123
|
+
- Taint for Swift/Objective-C sources (URL-scheme parameters to WKWebView / file sinks).
|
|
124
|
+
|
|
125
|
+
Part of the [Swift analyzer epic](https://github.com/mlaify/AttackMap/issues/204).
|
|
126
|
+
|
|
127
|
+
## Development
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
pip install -e ".[dev]"
|
|
131
|
+
pytest -q
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
[MIT](LICENSE). Copyright (c) 2026 Matthew Davis and AttackMap Contributors.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "attackmap-analyzer-swift"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Swift ecosystem analyzer plugin for AttackMap: Vapor/Hummingbird routes with route-level auth, the iOS/macOS app attack surface, and a SwiftPM/CocoaPods/Carthage SBOM."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{name = "Matthew Davis", email = "mlaify@mlaify.io"},
|
|
15
|
+
{name = "AttackMap Contributors"},
|
|
16
|
+
]
|
|
17
|
+
maintainers = [
|
|
18
|
+
{name = "Matthew Davis", email = "mlaify@mlaify.io"},
|
|
19
|
+
]
|
|
20
|
+
keywords = [
|
|
21
|
+
"security",
|
|
22
|
+
"static-analysis",
|
|
23
|
+
"appsec",
|
|
24
|
+
"defensive-security",
|
|
25
|
+
"attackmap",
|
|
26
|
+
"attackmap-plugin",
|
|
27
|
+
"swift",
|
|
28
|
+
]
|
|
29
|
+
classifiers = [
|
|
30
|
+
"Development Status :: 4 - Beta",
|
|
31
|
+
"Intended Audience :: Developers",
|
|
32
|
+
"Intended Audience :: Information Technology",
|
|
33
|
+
"Intended Audience :: System Administrators",
|
|
34
|
+
"Operating System :: OS Independent",
|
|
35
|
+
"Programming Language :: Python :: 3",
|
|
36
|
+
"Programming Language :: Python :: 3.11",
|
|
37
|
+
"Programming Language :: Python :: 3.12",
|
|
38
|
+
"Programming Language :: Python :: 3.13",
|
|
39
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
40
|
+
"Topic :: Security",
|
|
41
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
42
|
+
"Typing :: Typed",
|
|
43
|
+
]
|
|
44
|
+
dependencies = [
|
|
45
|
+
"pydantic>=2.7.0",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
core = [
|
|
50
|
+
"attackmap>=0.6.0",
|
|
51
|
+
]
|
|
52
|
+
dev = [
|
|
53
|
+
"pytest>=8.0.0",
|
|
54
|
+
"build>=1.2.0",
|
|
55
|
+
"attackmap>=0.6.0",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[project.urls]
|
|
59
|
+
Homepage = "https://github.com/mlaify/attackmap-analyzer-swift"
|
|
60
|
+
Repository = "https://github.com/mlaify/attackmap-analyzer-swift"
|
|
61
|
+
Issues = "https://github.com/mlaify/attackmap-analyzer-swift/issues"
|
|
62
|
+
Changelog = "https://github.com/mlaify/attackmap-analyzer-swift/blob/main/CHANGELOG.md"
|
|
63
|
+
"AttackMap core" = "https://github.com/mlaify/AttackMap"
|
|
64
|
+
|
|
65
|
+
[project.entry-points."attackmap.analyzers"]
|
|
66
|
+
swift = "attackmap_analyzer_swift:SwiftAnalyzer"
|
|
67
|
+
objc = "attackmap_analyzer_swift:ObjCAnalyzer"
|
|
68
|
+
|
|
69
|
+
[tool.setuptools]
|
|
70
|
+
package-dir = {"" = "src"}
|
|
71
|
+
|
|
72
|
+
[tool.setuptools.packages.find]
|
|
73
|
+
where = ["src"]
|
|
74
|
+
|
|
75
|
+
[tool.pytest.ini_options]
|
|
76
|
+
testpaths = ["tests"]
|