Skip to content
Report library
Purpose / Other

Expo Brownfield Skill Security Audit

What the author says it does (original text)

Framework (OSS). Integrate Expo and React Native into an existing native iOS or Android app. Use when the user mentions brownfield, embedding React Native in a native app, AAR/XCFramework, or adding Expo to an existing Kotlin/Swift project. Covers both the isolated approach and the integrated approach.

Independent security check

Do not install or run it yet

Files checked
6
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: 1
Medium risk

Install steps execute mutable remote packages, including an administrator-level CocoaPods install

Source references: 3
What we found

Project creation uses the time-varying `@latest` tag, feedback uses `npx --yes ...@latest`, and the CocoaPods prerequisite recommends globally installing an unpinned Gem with `sudo gem install`. These commands trust whichever package and dependencies the registries serve at execution time.

Why this matters

If a registry account, package, or dependency chain is compromised, downloaded code could run with the developer's privileges; content installed through sudo can also alter the system Ruby environment. Unpinned versions additionally make behavior non-reproducible without any attack.

The visible instructions contain three concrete trust changes: `create-expo-app@latest` and `submit-expo-feedback@latest` select the current release, while the unversioned CocoaPods installation runs through `sudo gem install`. These are ordinary operations for the stated Expo workflow, not evidence of malicious intent, but registry and dependency changes affect what code executes. Users can request pinned versions and dependency locks and avoid an administrator-level global install when unnecessary.

SKILL.md:44In the instructionsOpen original file
The integrated approach additionally requires **CocoaPods** on iOS (`sudo gem install cocoapods`). The isolated approach does **not** require CocoaPods or any RN tooling in the consuming native app.
Show 2 other places
SKILL.md:50In the instructionsOpen original file
```shnpx create-expo-app@latest my-project --template default@sdk-55```
SKILL.md:56In the instructionsOpen original file
## Submitting FeedbackIf you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:```bashnpx --yes submit-expo-feedback@latest --category skills --subject "expo-brownfield" "<actionable feedback>"```Only submit when you have something specific and actionable to report. Include as much relevant context as possible.
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

The feedback flow may send project or error context to an external service

Source references: 1
What we found

The Skill recommends running a downloaded feedback utility and asks for as much relevant context as possible. Build-error context often contains local paths, internal package names, repository details, logs, or configuration, but the text does not identify the recipient, transmitted fields, or a redaction step.

Why this matters

If raw logs or project details are included, proprietary information, internal infrastructure names, or credentials accidentally present in logs may leave the user's machine.

The feedback flow is optional and purpose-specific, and the visible text does not show automatic collection of the whole project. However, it asks the user to pass as much relevant context as possible to a freshly downloaded feedback tool. Pasting unredacted logs could disclose local paths, internal names, configuration, or tokens. Users should confirm the recipient and transmitted fields and submit only reviewed, redacted minimum context.

SKILL.md:56In the instructionsOpen original file
## Submitting FeedbackIf you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:```bashnpx --yes submit-expo-feedback@latest --category skills --subject "expo-brownfield" "<actionable feedback>"```Only submit when you have something specific and actionable to report. Include as much relevant context as possible.If an AI agent repeatedly failed or the user had to take over an Expo task, load the expo-skill-feedback skill and follow its eval-candidate flow instead of reusing the command above.
Could it delete files or keep running?Looks for broad file deletion, disk overwrites, and programs set to start automatically.Risks found: 1
High risk

“prebuild --clean” may regenerate and overwrite existing native projects

Source references: 2
What we found

The integrated guide first places existing Android/iOS projects in Expo's standard native directories, while troubleshooting later recommends regenerating native projects from scratch. In a brownfield app, those directories may contain pre-existing business code and project settings that Expo did not generate.

Why this matters

A clean prebuild may delete or replace manual native changes in android/ or ios/, including source code, signing configuration, build phases, or project settings.

The guide permits moving existing native projects into Expo's `android/` and `ios/` directories, while troubleshooting later recommends regenerating integrated native projects “from scratch” with `prebuild --clean`. If those directories contain hand-written code or settings not represented in Expo configuration, the clean regeneration may replace or remove them. Users should require documented preservation behavior and run it only on committed or backed-up work.

references/brownfield-integrated.md:33In the instructionsOpen original file
## 2) Place native projects under the Expo projectA standard React Native project keeps native code under `android/` and `ios/`. Move the existing native projects in:```shmkdir my-project/androidmv /path/to/your/android-project my-project/android/# repeat for ios/```
Show 1 other places
references/troubleshooting.md:7In the instructionsOpen original file
**Symptom:** Gradle or Xcode build fails after a config change, dependency upgrade, or Expo SDK bump.- **Integrated approach** — regenerate native projects from scratch:  ```sh  npx expo prebuild --clean  ```  Then `cd ios && pod install` and re-open the `.xcworkspace`.- **Isolated approach** — clear the local Maven cache and rebuild the artifact:
Could it bypass safety checks?Looks for skipped website security checks, excessive file access, or actions that skip your approval.Risks found: 2
Medium risk

The guide requires disabling Xcode user-script sandboxing

Source references: 4
What we found

The integrated flow explicitly sets `ENABLE_USER_SCRIPT_SANDBOXING` to No and adds a build phase that sources `.xcode.env`, `.xcode.env.local`, and `.xcode.env.updates`, then executes a Node-resolved dependency script. Disabling the sandbox reduces filesystem restrictions on those build scripts.

Why this matters

If an environment file, Pod, or Node dependency is tampered with, its script could read or modify more files under the builder's account. Signing material and environment credentials available in CI could also be exposed.

This is an active iOS integration requirement, not merely a warning: it tells users to disable Xcode's user-script sandbox and add a build phase that sources several environment files before executing a React Native script resolved from `node_modules`. If those files or dependencies are maliciously altered, the build script has fewer file-access restrictions. Users can ask why the setting must be disabled globally and restrict it to trusted builds with locked dependencies.

references/brownfield-integrated.md:350In the instructionsOpen original file
#### 1. Disable user script sandboxingIn Xcode, select your project → app target → **Build Settings**, search for `ENABLE_USER_SCRIPT_SANDBOXING`, and set it to **No**. CocoaPods' Hermes scripts need to switch between debug and release engine binaries at build time, which sandboxing blocks.
Show 3 other places
references/brownfield-integrated.md:358In the instructionsOpen original file
```shif [[ -f "$PODS_ROOT/../.xcode.env" ]]; then  source "$PODS_ROOT/../.xcode.env"fiif [[ -f "$PODS_ROOT/../.xcode.env.local" ]]; then  source "$PODS_ROOT/../.xcode.env.local"fi
references/brownfield-integrated.md:381In the instructionsOpen original file
if [[ -f "$PODS_ROOT/../.xcode.env.updates" ]]; then  source "$PODS_ROOT/../.xcode.env.updates"fiif [[ -f "$PODS_ROOT/../.xcode.env.local" ]]; then  source "$PODS_ROOT/../.xcode.env.local"fi`"$NODE_BINARY" --print "require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'"````
references/brownfield-integrated.md:354In the instructionsOpen original file
#### 2. Add a Run Script phase to embed the JS bundleOn the app target's **Build Phases** tab, add a new **Run Script** phase **before** `[CP] Embed Pods Frameworks`. This phase bundles JS for release builds and is skipped automatically in debug (Metro serves the bundle then).
Low risk

The install command does not pin a dependency version

Source references: 2
What we found

The installation command does not specify dependency versions. The same command may download different code later, so what you install can differ from what was checked.

Why this matters

A later install may download different code even though the command and this report have not changed.

The Expo template is pinned to SDK 55, but the `create-expo-app@latest` runner itself is not pinned. The same command may therefore execute a newer CLI and dependency tree at a later date. This does not mean the Expo SDK is unpinned or that the package was compromised. A user can ask for a fixed CLI version or inspect the resolved version first.

SKILL.md:51In the instructionsOpen original file
```shnpx create-expo-app@latest my-project --template default@sdk-55```
Show 1 other places
SKILL.md:48In the instructionsOpen original file
**Expo SDK 55 is the minimum supported version for brownfield integration.** Earlier SDKs lack `expo-brownfield`, the required `ExpoReactHostFactory` / `ExpoReactNativeFactory` entry points, and the current autolinking surface. When creating the Expo project, always pin the SDK explicitly:```shnpx create-expo-app@latest my-project --template default@sdk-55```
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.No risks found
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

5 instruction sections

The Skill offers two ways to add Expo/React Native to an existing native app: an isolated flow that produces AAR/XCFramework artifacts, and an integrated flow that directly changes Gradle, CocoaPods, and native startup code.

View source
SKILL.md:10In the instructionsOpen original file
Expo supports two distinct ways to add React Native to a brownfield project:| Approach       | What ships to the native app                                        | When to choose                                                                   || -------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- || **Isolated**   | Prebuilt AAR / XCFramework                                          | Native team doesn't need Node or RN tooling; RN code can live in a separate repo || **Integrated** | React Native sources added to the existing Gradle / CocoaPods build | One team owns everything; comfortable with RN tooling; wants a single build      |

The integrated flow adds Internet access to the main Android manifest and permits cleartext HTTP in the debug manifest so the app can reach the local Metro development server. Cleartext is scoped to the debug variant, while Internet access is added to the main manifest.

View source
references/brownfield-integrated.md:164In the instructionsOpen original file
### `AndroidManifest.xml`Add the `INTERNET` permission to your main manifest at `app/src/main/AndroidManifest.xml`:```xml<uses-permission android:name="android.permission.INTERNET" />```In the debug-variant manifest at `app/src/debug/AndroidManifest.xml`, enable cleartext traffic so the app can talk to the local Metro bundler over HTTP:```xml<application  android:usesCleartextTraffic="true"  tools:targetApi="28"

The isolated Android build publishes to local Maven by default and can be configured for public or private remote repositories; private repository URLs and credentials may be read from environment variables at publication time.

View source
references/brownfield-isolated.md:120In the instructionsOpen original file
Produces an AAR and publishes it to the local Maven repository at `~/.m2`. The Maven coordinates come from the plugin config — e.g. `com.example:mybrownfield:1.0.0`.#### Publishing the Android AARThe plugin's `publishing` option controls where the AAR is published. When unset, it defaults to local Maven. To push to other targets (e.g. a shared CI Maven, an internal Artifactory/Nexus, or a folder pulled into another build), declare the publications explicitly:
references/brownfield-isolated.md:149In the instructionsOpen original file
              },              {                "type": "remotePrivate",                "name": "artifactory",                "url": { "variable": "ARTIFACTORY_URL" },                "username": { "variable": "ARTIFACTORY_USER" },                "password": { "variable": "ARTIFACTORY_TOKEN" }              }            ]          }        }      ]    ]  }}```Supported `type` values: `localMaven`, `localDirectory`, `remotePublic`, `remotePrivate`. For private repos, credentials and URL accept either inline strings or `{ "variable": "ENV_VAR_NAME" }` to read from the environment at publish time.

The Skill contains commands that download and run package-manager content, generate native projects, build binary artifacts, and alter application build configuration; it is not read-only documentation.

View source
SKILL.md:48In the instructionsOpen original file
**Expo SDK 55 is the minimum supported version for brownfield integration.** Earlier SDKs lack `expo-brownfield`, the required `ExpoReactHostFactory` / `ExpoReactNativeFactory` entry points, and the current autolinking surface. When creating the Expo project, always pin the SDK explicitly:```shnpx create-expo-app@latest my-project --template default@sdk-55```
references/brownfield-isolated.md:112In the instructionsOpen original file
## 2) Build the native libraries### Android```shnpx expo-brownfield build:android```Produces an AAR and publishes it to the local Maven repository at `~/.m2`. The Maven coordinates come from the plugin config — e.g. `com.example:mybrownfield:1.0.0`.
Start here · InstructionsSKILL.md
expo-brownfield
Lines connect the instruction file to its sections, not an observed execution order. Select a section to read the source.

File reference map

References: 14
Files making referencesReferenced content
Lines show actual file references, not execution order. Select a node to highlight its connections and inspect the files and source locations. Dashed lines include files that still need locating.
Files and check records6 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
  • references/brownfield-integrated.mdFull text included
  • references/brownfield-isolated.mdFull text included
  • references/comparison.mdFull text included
  • references/troubleshooting.mdFull text included
  • agents/openai.yamlFull 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
  • agents/openai.yamlSupporting file
  • references/brownfield-integrated.mdSupporting file
  • references/brownfield-isolated.mdSupporting file
  • references/comparison.mdSupporting file
  • references/troubleshooting.mdSupporting file

Operations mentioned in code and instructions

Connect to websites
SKILL.md:35In the instructionsOpen original file
More information available at https://docs.expo.dev/brownfield/overview/
references/brownfield-integrated.md:65In the instructionsOpen original file
Register the React Native Gradle plugin and Expo autolinking. Reference: [bare-minimum template `settings.gradle`](https://github.com/expo/expo/blob/main/templates/expo-template-bare-minimum/android/settings.gradle).
references/brownfield-integrated.md:123In the instructionsOpen original file
    mavenCentral()    maven { url 'https://www.jitpack.io' }  }
Install extra software packages
SKILL.md:51In the instructionsOpen original file
```shnpx create-expo-app@latest my-project --template default@sdk-55```
SKILL.md:59In the instructionsOpen original file
```bashnpx --yes submit-expo-feedback@latest --category skills --subject "expo-brownfield" "<actionable feedback>"```
references/brownfield-integrated.md:28In the instructionsOpen original file
```shnpx create-expo-app@latest my-project --template default@sdk-55```
Run commands
SKILL.md:58In the instructionsOpen original file
If you encounter errors, misleading or outdated information in this skill, report it so Expo can improve:```bashnpx --yes submit-expo-feedback@latest --category skills --subject "expo-brownfield" "<actionable feedback>"
Change files
references/brownfield-integrated.md:39In the instructionsOpen original file
mkdir my-project/androidmv /path/to/your/android-project my-project/android/# repeat for ios/
references/troubleshooting.md:16In the instructionsOpen original file
  ```sh  rm -rf ~/.m2/repository/<group>/<libraryName>  npx expo-brownfield build:android
Read files
references/brownfield-integrated.md:289In the instructionsOpen original file
require 'json'podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
Read keys or account settings
references/brownfield-integrated.md:359In the instructionsOpen original file
```shif [[ -f "$PODS_ROOT/../.xcode.env" ]]; then  source "$PODS_ROOT/../.xcode.env"
references/brownfield-integrated.md:360In the instructionsOpen original file
if [[ -f "$PODS_ROOT/../.xcode.env" ]]; then  source "$PODS_ROOT/../.xcode.env"fi
references/brownfield-integrated.md:362In the instructionsOpen original file
fiif [[ -f "$PODS_ROOT/../.xcode.env.local" ]]; then  source "$PODS_ROOT/../.xcode.env.local"
Lines read
1,200
File checksum (to compare versions)
d290920cb769aae047cc8632c572b4ff7d35f9c191cd7692f54c532302839620