88"io"
99"os"
1010"os/exec"
11+ "path/filepath"
1112"regexp"
1213"strings"
1314"time"
@@ -136,7 +137,18 @@ func (g *Generator) getInstalledPackages() ([]DpkgPackage, error) {
136137}
137138
138139func (g * Generator )getPackageLicense (packageName string ) (string ,string ) {
139- copyrightPath := fmt .Sprintf ("/usr/share/doc/%s/copyright" ,packageName )
140+ // Sanitize package name to prevent path traversal
141+ cleanName := filepath .Clean (packageName )
142+ if strings .Contains (cleanName ,".." )|| strings .HasPrefix (cleanName ,"/" )|| strings .Contains (cleanName ,string (filepath .Separator )) {
143+ return "NOASSERTION" ,"NOASSERTION"
144+ }
145+
146+ copyrightPath := filepath .Join ("/usr/share/doc" ,cleanName ,"copyright" )
147+
148+ // Verify the resolved path is within the expected directory
149+ if ! strings .HasPrefix (copyrightPath ,"/usr/share/doc/" ) {
150+ return "NOASSERTION" ,"NOASSERTION"
151+ }
140152
141153content ,err := os .ReadFile (copyrightPath )
142154if err != nil {
@@ -211,7 +223,13 @@ func (g *Generator) packageToSPDX(pkg DpkgPackage, id int) spdx.Package {
211223}
212224
213225func (g * Generator )calculatePackageChecksum (packageName string )string {
214- cmd := exec .Command ("dpkg" ,"-L" ,packageName )
226+ // Sanitize package name to prevent command injection
227+ cleanName := filepath .Clean (packageName )
228+ if strings .Contains (cleanName ,".." )|| strings .HasPrefix (cleanName ,"/" )|| strings .Contains (cleanName ,string (filepath .Separator )) {
229+ return ""
230+ }
231+
232+ cmd := exec .Command ("dpkg" ,"-L" ,cleanName )
215233output ,err := cmd .Output ()
216234if err != nil {
217235return ""
@@ -235,7 +253,21 @@ func (g *Generator) calculatePackageChecksum(packageName string) string {
235253}
236254
237255func hashFile (path string )string {
238- file ,err := os .Open (path )
256+ // Sanitize path to prevent path traversal
257+ cleanPath := filepath .Clean (path )
258+
259+ // Reject paths with traversal attempts or that aren't absolute
260+ if strings .Contains (cleanPath ,".." )|| ! filepath .IsAbs (cleanPath ) {
261+ return ""
262+ }
263+
264+ // Verify it's a regular file (not a symlink to outside, directory, etc.)
265+ info ,err := os .Lstat (cleanPath )
266+ if err != nil || ! info .Mode ().IsRegular () {
267+ return ""
268+ }
269+
270+ file ,err := os .Open (cleanPath )
239271if err != nil {
240272return ""
241273}