Safeguard
Supply Chain•

How many dependency ecosystems does a cross-platform app have?

A React Native or Flutter app often has three or more dependency ecosystems. Where each lockfile lives and why one scan of one file misses most of the app.

Safeguard Security Team
3 min read

Usually at least three. A React Native app has JavaScript packages, plus iOS pods or Swift packages, plus Android Gradle libraries. A Flutter app has Dart packages in the same pattern. Each layer has its own lockfile and its own advisories, so scanning one file covers only a slice of the app.

The layers

LayerReact NativeFlutter
Shared codenpm packagesDart packages in pubspec
iOS nativeCocoaPods or Swift packagesCocoaPods or Swift packages
Android nativeGradle librariesGradle libraries
Runtime engineJavaScript engine and bridge codeFlutter engine

Apple's third-party SDK requirements list shows how real this is. It names cross-platform pieces such as Flutter itself, Capacitor, Cordova, hermes, and many Flutter plugins like path_provider, url_launcher, image_picker_ios and shared_preferences_ios. When you add a plugin, you add native iOS and Android code behind it.

Which lockfile where

  • Dart. The Dart documentation says to commit pubspec.lock for application packages, and not for regular packages.
  • iOS. Podfile.lock records the exact pod versions, and the CocoaPods guide says to keep it under version control.
  • Android. Gradle's lock files are gradle.lockfile per project, if you turn locking on.
  • JavaScript. Commit your package manager's lockfile.

Different teams often own different files. The risk is that nobody owns the sum.

Steps for a full inventory

  1. List each lockfile in the repository, including those under the ios and android folders.
  2. Scan each one, or generate an SBOM that merges them.
  3. Tag each finding with its layer so the right person fixes it.
  4. For a vulnerable plugin, find the package it came from and check for a newer plugin version.
  5. Re-run on each release.

An example of the sum

Take a Flutter app with a dozen plugins. The Dart lockfile lists the plugins and their Dart dependencies. Each plugin that touches the camera, files or the network also brings Swift or Kotlin code and often pods or Gradle libraries of its own. Those native libraries are not in the Dart lockfile at all. They are resolved when the iOS and Android projects build, and they land in Podfile.lock and in the Gradle graph.

A scan that reads only the Dart file reports on the plugins. A scan that reads all three reports on the code that actually runs on the phone.

Why fixes are slower here

A vulnerable native library behind a plugin cannot be patched by editing your app. You wait for the plugin to bump the library, then update the plugin, then rebuild. Knowing which plugin pulled it in is half the work, which is what the dependency tree gives you.

For the Kotlin Multiplatform angle, see Kotlin Multiplatform supply chain risks.

Quick check

Is the JavaScript lockfile enough for a React Native app?

No. The iOS and Android layers have their own lockfiles and their own known vulnerabilities.

Should I commit pubspec.lock?

For an application, yes. Dart's documentation recommends it.

Safeguard's dependency and SBOM scanning scans dependency manifests and SBOMs, so you can point it at each layer of the repository. It does not analyze compiled mobile binaries. Try a free scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.