DEV Community

Cover image for How to generate an SBOM for a Flutter app
Catalin Shipmark
Catalin Shipmark

Posted on Originally published at shipmark.eu

How to generate an SBOM for a Flutter app

In short

  • Your pubspec.lock already lists every Dart and Flutter package in the app, with exact versions.
  • Turn it into a CycloneDX SBOM, then add the native side: ios/Podfile.lock and the Android Gradle dependencies.
  • Generate a new SBOM for every release and keep it with the app's technical documentation.

Why a Flutter app needs an SBOM now

The EU Cyber Resilience Act (Regulation (EU) 2024/2847) applies to software placed on the EU market as part of a commercial activity. That includes most mobile apps published by companies, even free ones.

Annex I, Part II asks manufacturers to identify and document the components of their product, including by drawing up a software bill of materials (SBOM) in a commonly used, machine-readable format, covering at least the top-level dependencies. The full requirements apply from 11 December 2027. Since 11 September 2026, actively exploited vulnerabilities must already be reported to ENISA within 24 hours, and an SBOM is how you find out quickly whether one affects your app.

Step 1. Find and read pubspec.lock

Every Flutter project has a pubspec.lock in its root, created by flutter pub get. For applications, Dart recommends committing it to version control, so it also tells you exactly what shipped in each release.

packages:
  http:
    dependency: "direct main"
    description:
      name: http
      url: "https://pub.dev"
    source: hosted
    version: "1.2.2"
  collection:
    dependency: transitive
    source: hosted
    version: "1.18.0"
Enter fullscreen mode Exit fullscreen mode

Three fields matter for the SBOM:

Field What it tells you
version The exact version resolved for the build.
dependency direct main are your top-level dependencies, transitive are pulled in by others, and direct dev are build tools that do not ship in the app.
source hosted means pub.dev. git and path packages need extra care, because public vulnerability databases cannot match them by version.

Step 2. Turn it into a CycloneDX SBOM

Option A: in your browser, in seconds

Drop the file on the Shipmark free scanner. It reads pubspec.lock locally, builds a CycloneDX 1.6 SBOM with a package URL (pkg:pub/…) for every component, marks development-only packages as excluded and checks each version against OSV.dev. The file never leaves your browser.

Option B: in the terminal or in CI

To check the lockfile for known vulnerabilities from the command line, Google's OSV-Scanner reads it directly:

osv-scanner scan -L pubspec.lock
Enter fullscreen mode Exit fullscreen mode

General-purpose SBOM generators such as cdxgen and Syft can also produce CycloneDX files. Check their documentation for the Dart ecosystem before relying on them in CI.

Step 3. Do not forget the native side

This is the part most Flutter SBOMs miss. Plugins such as camera, maps, payments or analytics bring native libraries with them, and those are not in pubspec.lock.

  • iOS: ios/Podfile.lock lists every CocoaPod. If you use Swift Package Manager, look for Package.resolved inside the Xcode workspace.
  • Android: enable Gradle dependency locking and commit the result. Running ./gradlew dependencies --write-locks in the android folder creates gradle.lockfile.

The Shipmark scanner accepts all three files, so you can produce one SBOM per platform and keep them together.

Step 4. Make it part of every release

  • Generate the SBOM from the exact commit you tag for the store release, not from the main branch on another day.
  • Name it after the app and the version, for example orderly-4.2.0.cdx.json.
  • Store it with the technical file. The CRA requires that documentation to be kept for ten years or for the support period, whichever is longer.
  • Re-check old SBOMs regularly. A release that was clean when you shipped it can be affected by a vulnerability published next month.

To automate this on GitHub, the free Shipmark SBOM action reads pubspec.lock, Podfile.lock and gradle.lockfile on every build or release, writes one CycloneDX 1.6 SBOM for the whole app and checks it against OSV.dev:

- uses: actions/checkout@v4
- uses: shipmark-eu/sbom-action@v1
  with:
    output: sbom-${{ github.ref_name }}.cdx.json
Enter fullscreen mode Exit fullscreen mode

Common questions

Do I have to publish the SBOM?

No. It belongs to the technical documentation and must be made available to market surveillance authorities on request. Sharing it with users is optional.

We are an agency. Is this our job or the client's?

Legally, the obligations sit with the manufacturer, usually the company that publishes the app under its own name. In practice, the team that maintains the code is the one that can produce the SBOM, so clients will ask their agency.

Does the Flutter SDK itself belong in the SBOM?

The Flutter and Dart SDKs appear in pubspec.lock only as source: sdk, without a usable version. Record the Flutter version you built with (from flutter --version) alongside the SBOM.

Try it on your own app: the free Shipmark scanner builds a CycloneDX SBOM from a lockfile in the browser and checks it against OSV.dev. Not sure the CRA applies? Use the six-question CRA check.

Also see: How to generate an SBOM for a React Native app. This guide summarises Regulation (EU) 2024/2847 for practical use. It is not legal advice.


Originally published on shipmark.eu, where the guide is kept up to date. More guides for app teams: shipmark.eu/guides.

Top comments (0)