Repository: go
Issue: proposal: runtime/debug: add standard library dependency information to `debug.BuildInfo`
Labels: Proposal

The information provided by the `debug.BuildInfo` struct, particularly in the `Deps` field, is useful for vulnerability detection. Many open-source and commercial vulnerability scanners are now capable of parsing `dep` entries in the `BuildInfo` data embedded in binaries to identify vulnerable third-party library dependencies that contributed to the build process.

Some commercial vulnerability scanners have gone a step further and are using the value of the `GoVersion` field in the same struct to identify vulnerable standard library packages in the version of the Go toolchain that built the binary - for example, they report that binaries with a `GoVersion` between `go1.19` and `go1.19.7` or `go1.20` and `go1.20.2` are affected by [CVE-2023-24536](https://nvd.nist.gov/vuln/detail/CVE-2023-24536). In general, this approach overestimates the number of vulnerabilities a binary is affected by, because a vulnerable standard library package may not be imported in a binary's transitive dependency tree.

To improve the accuracy of such scanners, it may be beneficial to add a new field to the `BuildInfo` struct containing a list of all standard library packages that, directly or indirectly, contributed to the build process. It could be as simple as a string slice listing the package names, given that the standard library version could be derived from the Go toolchain version that built the binary, which is already available in the `GoVersion` field.

## Proposal

Add the following field to the `debug.BuildInfo` struct:

```
// BuildInfo represents the build information read from a Go binary.
type BuildInfo struct {
	// StdlibPkgs describes all the standard library packages, both direct and
	// indirect, that contributed to the build of this binary.
	StdlibPkgs []string
}
```

When embedded into the binary, the data structure becomes a list of lexicographically-ordered lines prepended with the keyword `stdlibpkg`, per the current `BuildInfo` serialisation format, e.g.:

```
stdlibpkg	fmt
stdlibpkg	io
stdlibpkg	io/fs
stdlibpkg	io/ioutil
[...]
```

## Open questions

* **Should vendorised packages identified by the `cmd/go/internal/load` API as belonging to the stdlib be filtered?** This covers `Package`s where `Standard` is true but `ImportPath` contains `/vendor/` or is prefixed with `vendor/`. My feeling is that they should - presumably information about these packages is already (or should instead be) exposed in the `Deps` field if it is required.
* **Should internal stdlib packages be filtered?** My feeling is that they shouldn't - there are vulndb reports for vulnerabilities that only affect specific internal packages (e.g. [GO-2022-0318](https://pkg.go.dev/vuln/GO-2022-0318)), and it seems appropriate to make that information available to scanners to improve detection accuracy.
* **Should symbol names be taken into consideration now?** vulndb reports include information about which symbols in a package are affected by a given vulnerability. I could see a future case for including in `StdlibPkgs` a list of used symbols for each stdlib package in order to improve detection accuracy further, in which case a data structure other than `[]string` would be appropriate, although that'd be a lot of extra information to embed.