Skip to content
Report library
Purpose / Development

Xcode Project Setup Skill Security Audit

What the author says it does (original text)

Safely modifies Xcode projects (.pbxproj) to add Swift Packages and link files. Use this skill whenever an iOS project needs dependencies installed (e.g. Firebase, Alamofire).

Independent security check

Do not install or run it yet

Files checked
5
Risks found
5
Could it run dangerous commands?Looks for programs run straight after downloading, remote control of your computer, and hidden commands.Risks found: 2
High risk

Selecting Crashlytics inserts a downloaded script that runs during later builds

Source references: 2
What we found

When a product name contains `FirebaseCrashlytics`, the tool adds a `/bin/sh` build phase that executes `Crashlytics/run` from the Firebase package checkout. That script's source is not included in the supplied material, so its full behavior cannot be verified here. The phase also declares the dSYM, executable, and GoogleService plist as readable inputs.

Why this matters

Later builds execute code from the resolved Firebase SDK with the developer's local privileges and expose application binaries, debug symbols, and configuration to it. A compromised dependency source or resolved version could therefore become a route to code execution or disclosure of build material.

When a product name contains `FirebaseCrashlytics`, the tool writes a `/bin/sh` build phase that will execute `Crashlytics/run` from the checked-out Firebase SDK during later builds. The phase declares dSYMs, the app executable, and the GoogleService plist as inputs. That script is absent from the supplied source, so its exact network or data-handling behavior cannot be verified here. A user can request documentation and pinning for Firebase, or restrict the phase's inputs and execution environment.

scripts/xcode_spm_setup/Sources/main.swift:43In the instructionsOpen original file
    var inputPaths = [        "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}",        "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${PRODUCT_NAME}",        "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist",        "$(TARGET_BUILD_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/GoogleService-Info.plist",        "$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)"    ]    if isUserScriptSandboxingEnabled(project: project) {        inputPaths.append("${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${PRODUCT_NAME}.debug.dylib")    }    let phase = PBXShellScriptBuildPhase(        files: [],        inputPaths: inputPaths,        outputPaths: [],        shellPath: "/bin/sh",        shellScript: "\"${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run\"\n",        runOnlyForDeploymentPostprocessing: false
Show 1 other places
scripts/xcode_spm_setup/Sources/main.swift:210In the instructionsOpen original file
        if products.contains(where: { $0.contains("FirebaseCrashlytics")}) {            print("Setting the debug format to DWARF with dSYMs")            setDwarfWithDsymDebugInformationFormat(project: pbxproj)            print("Adding the Crashlytics Run Script Build phase")            if !hasCrashlyticsRunScriptBuildPhase(project: pbxproj) {                addCrashlyticsRunScriptBuildPhase(project: pbxproj)            } else {                print("Crashlytics Run Script Build phase already exists")            }        }
Medium risk

The apparent version number is actually a range allowing future same-major updates

Source references: 2
What we found

The documentation presents the argument as a concrete version and instructs use of the latest one, but the code stores it with `upToNextMajorVersion` rather than pinning that version. A later resolution may therefore select an unreviewed newer minor or patch release.

Why this matters

Build contents can change with resolution time or cache state. A later compromised or incompatible package release may be downloaded, compiled, and incorporated into the app.

The documentation tells the agent to pass the latest version number, but the implementation converts it to an `.upToNextMajorVersion` requirement rather than an exact pin. Dependency resolution may therefore select a later, unreviewed release within the same major version. The tool's own `Package.resolved` pin does not pin the new dependency written into the user's Xcode project. Users can request exact-version support or commit and review the project's resolved lockfile.

SKILL.md:88In the instructionsOpen original file
### **CRITICAL: Always Use Latest SDK Version**To ensure access to the latest features and security fixes, always use the mostrecent version of the Firebase iOS SDK. Check for the latest release version at[https://github.com/firebase/firebase-ios-sdk/releases](https://github.com/firebase/firebase-ios-sdk/releases).- Use the most recent version number (e.g., `11.x.y`) in your commands instead  of hardcoded placeholders.
Show 1 other places
scripts/xcode_spm_setup/Sources/main.swift:151In the instructionsOpen original file
        } else {            packageRef = try rootObject.addSwiftPackage(                repositoryURL: repoURL,                 productName: products.first!,                 versionRequirement: .upToNextMajorVersion(versionRequirementString),                 targetName: target.name            )
Could it expose your files or keys?Looks for uploads of files containing passwords or keys, and keys written directly in the code.Risks found: 1
Medium risk

`--plist` can package any designated plist into application resources

Source references: 3
What we found

The implementation accepts an arbitrary plist path without checking its contents or whether it is inside the project, then adds the reference to the target's Resources build phase. Although intended for GoogleService configuration, it does not restrict the filename or sensitive fields.

Why this matters

If the agent or user supplies a plist containing private keys, service-account material, internal endpoints, or other secrets, it may enter the build artifact and be distributed with the app.

The path following `--plist` is accepted directly, with no visible filename, location, or content validation. If no same-named item exists, the tool references it and adds it to the selected target's Resources build phase. Thus, a sensitive plist supplied by an agent or user could be packaged into the app. This requires explicit use of `--plist`; the tool does not scan for files automatically. Users can restrict it to the expected `GoogleService-Info.plist`, require an in-project path, and inspect build resources.

scripts/xcode_spm_setup/Sources/main.swift:93In the instructionsOpen original file
        var plistPath: Path? = nil    if let plistIndex = arguments.firstIndex(of: "--plist"), plistIndex + 1 < arguments.count {        plistPath = Path(arguments[plistIndex + 1])        arguments.remove(at: plistIndex + 1)        arguments.remove(at: plistIndex)    }
Show 2 other places
scripts/xcode_spm_setup/Sources/main.swift:129In the instructionsOpen original file
                        // Only add if it doesn't already exist            if groupToAddTo?.children.contains(where: { $0.path == plistPath.lastComponent || $0.name == plistPath.lastComponent }) == false {                let fileRef = try groupToAddTo?.addFile(at: plistPath, sourceRoot: projectPath.parent())                                if let fileRef = fileRef, let buildPhase = target.buildPhases.first(where: { $0.buildPhase == .resources }) as? PBXResourcesBuildPhase {                    _ = try buildPhase.add(file: fileRef)                    print("Successfully added \(plistPath.lastComponent) to resources build phase.")                }
scripts/xcode_spm_setup/Sources/main.swift:121In the instructionsOpen original file
                // 1. Add Plist to the project (Optional)        if let plistPath = plistPath {            print("Adding \(plistPath.lastComponent) to project...")            let mainGroup = rootObject.mainGroup                        let appName = target.name            let groupToAddTo = mainGroup?.children.first(where: { $0.path == appName }) as? PBXGroup ?? mainGroup                        // Only add if it doesn't already exist            if groupToAddTo?.children.contains(where: { $0.path == plistPath.lastComponent || $0.name == plistPath.lastComponent }) == false {                let fileRef = try groupToAddTo?.addFile(at: plistPath, sourceRoot: projectPath.parent())                                if let fileRef = fileRef, let buildPhase = target.buildPhases.first(where: { $0.buildPhase == .resources }) as? PBXResourcesBuildPhase {                    _ = try buildPhase.add(file: fileRef)                    print("Successfully added \(plistPath.lastComponent) to resources build phase.")                }
Could it delete files or keep running?Looks for broad file deletion, disk overwrites, and programs set to start automatically.Risks found: 1
Medium risk

All changes are silently applied to the project's first native target

Source references: 5
What we found

The command has no target argument and does not select a user-named target; the implementation directly uses `nativeTargets.first`. Dependencies, product links, and Firebase build settings are then applied to that target.

Why this matters

In projects with extensions, tests, multiple apps, or a different target ordering, the tool can persistently modify the wrong target. The wrong component may receive SDKs, linker flags, or build scripts, potentially causing build failures or unintended telemetry.

The command has no target argument and the implementation directly selects `nativeTargets.first`, then applies package products and build settings to it. The documentation calls this the “main target,” but does not establish that the first target is the intended app target; multi-target projects could therefore be changed incorrectly. The operation is not entirely silent because progress is printed. A user can ask for explicit target selection and a pre-change preview.

scripts/xcode_spm_setup/Sources/main.swift:116In the instructionsOpen original file
                guard let target = pbxproj.nativeTargets.first else {            print("Error: No native targets found")            exit(1)        }        
Show 4 other places
scripts/xcode_spm_setup/Sources/main.swift:151In the instructionsOpen original file
        } else {            packageRef = try rootObject.addSwiftPackage(                repositoryURL: repoURL,                 productName: products.first!,                 versionRequirement: .upToNextMajorVersion(versionRequirementString),                 targetName: target.name            )        }
scripts/xcode_spm_setup/Sources/main.swift:176In the instructionsOpen original file
                        let dependency = XCSwiftPackageProductDependency(productName: product, package: packageRef)            pbxproj.add(object: dependency)                        if target.packageProductDependencies == nil { target.packageProductDependencies = [] }            target.packageProductDependencies?.append(dependency)                        let buildFile = PBXBuildFile(product: dependency)            pbxproj.add(object: buildFile)                        if frameworksBuildPhase?.files == nil { frameworksBuildPhase?.files = [] }            frameworksBuildPhase?.files?.append(buildFile)        }
SKILL.md:107In the instructionsOpen original file
**The provided `xcode_spm_setup` Swift script automatically handles BOTH ofthese steps for you.** By passing the list of modules as arguments, it safelyinjects the package dependency and automatically wires those modules to the maintarget's Frameworks build phase. You do not need to do any manual linking.
scripts/xcode_spm_setup/Sources/main.swift:81In the instructionsOpen original file
func main() {    let args = CommandLine.arguments    guard args.count >= 5 else {        print("Usage: swift run --package-path <path> xcode_spm_setup <Path/To/Project.xcodeproj> <RepoURL> <VersionRequirement> [--plist <Path/To/Plist>] <Product1> [Product2 ...]")        exit(1)
Could it bypass safety checks?Looks for skipped website security checks, excessive file access, or actions that skip your approval.No risks found
Could it mislead the AI or hide text?Checks the skill instructions for requests to ignore you, influence the report, or hide text in invisible characters.Risks found: 1
Low risk

The Skill uses an unsupported fee threat to pressure the agent

Source references: 1
What we found

The live instructions claim that a “hefty fee” will be applied for violating their rules, without identifying a charging party, contract, or user authorization. This is unrelated to the technical requirements of Xcode configuration and is pressure directed at the executing agent.

Why this matters

An agent may refuse user-authorized safe alternatives, over-prioritize these rules, or request extra tooling without a technical basis. The supplied material does not establish that any fee is real.

The live skill instructions claim that violating their rules will incur a “hefty fee.” Nothing supplied defines a billing mechanism or contractual basis, so the statement cannot itself charge the user. It is nevertheless an unrelated pressure tactic aimed at influencing the agent's decisions and could encourage undue compliance with the skill author's preferences. Users can ask the author to remove it and retain only technically justified restrictions consistent with user authorization.

SKILL.md:11In the instructionsOpen original file
## ⛔️ CRITICAL RULES & ENVIRONMENT CHECKSBefore performing any Xcode setup or file manipulation, you **MUST** adhere tothe following rules. A hefty fee will be applied if you violate them.
Could it change links or payment recipients without asking?Looks for forced referral or payment changes combined with instructions to hide the change.No risks found

Inside this skill

4 instruction sections

The Skill requires checking that Swift is installed and then runs its bundled configuration tool through `swift run`, instead of having the user add dependencies manually in Xcode.

View source
SKILL.md:38In the instructionsOpen original file
Because this skill relies entirely on a native Swift script, you must verify theenvironment:- Run `swift --version` before proceeding.- If the Swift command is not found, you must stop and recommend the user  install the Swift toolchain (e.g., via `xcode-select --install` on macOS), or  ask if you can attempt to install it for them. Do not attempt to proceed  without Swift.
SKILL.md:114In the instructionsOpen original file
1. **Locate the package path:** Find the absolute path to this skill's   `scripts/xcode_spm_setup` directory on disk.1. **Execute:** Run the native `swift run` command using the signature below:```bashswift run --package-path <PATH_TO_SKILL>/scripts/xcode_spm_setup xcode_spm_setup <ProjectPath.xcodeproj> <RepoURL> <VersionRequirement> [--plist <Optional/Path/To/Config.plist>] <Product1> [Product2 ...]```

The configuration tool directly rewrites the specified Xcode project: it can add a plist resource, a remote Swift Package and product links, and then saves the `.xcodeproj`.

View source
scripts/xcode_spm_setup/Sources/main.swift:121In the instructionsOpen original file
                // 1. Add Plist to the project (Optional)        if let plistPath = plistPath {            print("Adding \(plistPath.lastComponent) to project...")            let mainGroup = rootObject.mainGroup                        let appName = target.name            let groupToAddTo = mainGroup?.children.first(where: { $0.path == appName }) as? PBXGroup ?? mainGroup                        // Only add if it doesn't already exist            if groupToAddTo?.children.contains(where: { $0.path == plistPath.lastComponent || $0.name == plistPath.lastComponent }) == false {                let fileRef = try groupToAddTo?.addFile(at: plistPath, sourceRoot: projectPath.parent())                                if let fileRef = fileRef, let buildPhase = target.buildPhases.first(where: { $0.buildPhase == .resources }) as? PBXResourcesBuildPhase {                    _ = try buildPhase.add(file: fileRef)                    print("Successfully added \(plistPath.lastComponent) to resources build phase.")                }
scripts/xcode_spm_setup/Sources/main.swift:151In the instructionsOpen original file
        } else {            packageRef = try rootObject.addSwiftPackage(                repositoryURL: repoURL,                 productName: products.first!,                 versionRequirement: .upToNextMajorVersion(versionRequirementString),                 targetName: target.name            )        }
scripts/xcode_spm_setup/Sources/main.swift:222In the instructionsOpen original file
                // Write changes        try xcodeproj.write(path: projectPath)        print("Successfully updated Xcode project!")        

The tool itself depends on the remote XcodeProj package; the bundled resolution file records the currently selected revision and version.

View source
scripts/xcode_spm_setup/Package.swift:7In the instructionsOpen original file
    platforms: [.macOS(.v13)],    dependencies: [        .package(url: "https://github.com/tuist/XcodeProj.git", .upToNextMajor(from: "8.27.7")),    ],    targets: [        .executableTarget(            name: "xcode_spm_setup",            dependencies: ["XcodeProj"],            path: "Sources"        )
scripts/xcode_spm_setup/Package.resolved:31In the instructionsOpen original file
    {      "identity" : "xcodeproj",      "kind" : "remoteSourceControl",      "location" : "https://github.com/tuist/XcodeProj.git",      "state" : {        "revision" : "b1caa062d4aaab3e3d2bed5fe0ac5f8ce9bf84f4",        "version" : "8.27.7"      }
Start here · InstructionsSKILL.md
xcode-project-setup
Lines connect the instruction file to its sections, not an observed execution order. Select a section to read the source.
Files and check records5 files

Coverage and gaps

Content covered in each file

These are the source ranges included in this check, not a guarantee that every issue has been resolved.

  • SKILL.mdFull text included
  • scripts/xcode_spm_setup/.gitignoreFull text included
  • scripts/xcode_spm_setup/Package.resolvedFull text included
  • scripts/xcode_spm_setup/Package.swiftFull text included
  • scripts/xcode_spm_setup/Sources/main.swiftFull text included

This report is for the version above. We read the available code and instructions without running the skill or checking extra packages it installs. This is not a promise of safety: a different version or setup may behave differently.

  • SKILL.mdInstructions
  • scripts/xcode_spm_setup/.gitignoreSupporting file
  • scripts/xcode_spm_setup/Package.resolvedSupporting file
  • scripts/xcode_spm_setup/Package.swiftSupporting file
  • scripts/xcode_spm_setup/Sources/main.swiftSupporting file

Operations mentioned in code and instructions

Connect to websites
SKILL.md:92In the instructionsOpen original file
recent version of the Firebase iOS SDK. Check for the latest release version at[https://github.com/firebase/firebase-ios-sdk/releases](https://github.com/firebase/firebase-ios-sdk/releases).
SKILL.md:102In the instructionsOpen original file
1. Adding the package repository dependency (e.g.,   `https://github.com/Alamofire/Alamofire`).1. Selecting the target (e.g., `MyApp`), navigating to **General > Frameworks,
SKILL.md:127In the instructionsOpen original file
```bashswift run --package-path /Users/foo/.agents/skills/xcode-project-setup/scripts/xcode_spm_setup xcode_spm_setup MyApp.xcodeproj https://github.com/Alamofire/Alamofire 5.8.1 Alamofire```
Run commands
SKILL.md:118In the instructionsOpen original file
```bashswift run --package-path <PATH_TO_SKILL>/scripts/xcode_spm_setup xcode_spm_setup <ProjectPath.xcodeproj> <RepoURL> <VersionRequirement> [--plist <Optional/Path/To/Config.plist>] <Product1> [Product2 ...]
SKILL.md:126In the instructionsOpen original file
```bashswift run --package-path /Users/foo/.agents/skills/xcode-project-setup/scripts/xcode_spm_setup xcode_spm_setup MyApp.xcodeproj https://github.com/Alamofire/Alamofire 5.8.1 Alamofire
SKILL.md:137In the instructionsOpen original file
```bashswift run --package-path /Users/foo/.agents/skills/xcode-project-setup/scripts/xcode_spm_setup xcode_spm_setup MyApp.xcodeproj https://github.com/firebase/firebase-ios-sdk 11.0.0 --plist MyApp/GoogleService-Info.plist FirebaseCore FirebaseA 
Change files
scripts/xcode_spm_setup/Sources/main.swift:223In the instructionsOpen original file
        // Write changes        try xcodeproj.write(path: projectPath)        print("Successfully updated Xcode project!")
Lines read
446
File checksum (to compare versions)
15e533a3f5a4c476b5695bca1dfbdf5dfc61a4d01a357525c2d3d7717002dfa9