Yes. Gradle lets you pass an initialization script on the command line that applies the CycloneDX plugin to the root project, so you can produce an SBOM without touching build.gradle. The plugin documents this approach for CI and for builds you do not own.
When this is useful
Three situations come up repeatedly.
- You run security tooling centrally and do not want to open pull requests against fifty repositories just to add a plugin line.
- You are assessing a project owned by someone else, such as an acquisition target or an open source dependency you are evaluating.
- You want a trial run before committing to a permanent change.
In each case you want an SBOM from the build exactly as it is, with no edits to the repository.
How it works
An initialization script runs before the build files are evaluated. It can add a plugin to the script classpath and apply it to the root project. You then call the plugin task as normal and point Gradle at the script.
Kotlin DSL, saved as init.gradle.kts:
import org.cyclonedx.gradle.CyclonedxPlugin
initscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath("org.cyclonedx.bom:org.cyclonedx.bom.gradle.plugin:VERSION")
}
}
rootProject {
apply<CyclonedxPlugin>()
}
Run it:
./gradlew cyclonedxBom --init-script init.gradle.kts
The Groovy version has the same shape, with apply plugin and a classpath string. Replace VERSION with the plugin release you have chosen.
Steps for a safe run
- Pin the plugin to an exact version in the classpath line. Never use a floating version in CI.
- Keep the init script in a central repository your platform team controls, and review changes to it like any other pipeline code.
- Run it in a clean checkout on a build agent, not a developer laptop with cached credentials.
- Save the output under a name that includes the repository, commit and plugin version.
- Compare the first result with a few dependencies you know to be there.
A caution about init scripts
An initialization script runs with the full power of the build. It can declare repositories, add dependencies to the build classpath and execute arbitrary code. That is exactly why teams like it, and also why it needs care. A script that pulls a plugin from a repository you do not control is a supply chain entry point.
So treat the init script as security sensitive: pin versions, restrict who can edit it, and prefer an internal mirror of the plugin repository if your environment has one. If the project you are scanning is untrusted, run the build in an isolated environment, because Gradle executes the project's own build scripts too, and those are code.
What you get
The aggregate task produces its report under the root project's build directory, along with the per-project direct files it consumes. Defaults are JSON and XML. Because you applied the plugin only at the root, the aggregate covers the root and contributing subprojects.
Limits
The plugin needs Gradle 8.4 or newer, so an old wrapper will fail regardless of how you apply it. And the init script approach changes nothing about what the SBOM can see: it still reflects resolved dependencies, not code copied into the repository or fetched at runtime.
If you want to see what a dependency set looks like to a scanner without a build, Safeguard's SBOM and dependency scanning reads manifests directly, and there is a free scan.
Quick check
Does the init script change the repository?
No. It lives outside the project and is passed on the command line, so the repository stays untouched.
Is it safe to run on an untrusted project?
Only in an isolated environment. Gradle runs the project's own build scripts, which can execute code.
Sources
Last reviewed: 19 October 2026.