Skip to content

Instantly share code, notes, and snippets.

@tlusser
Created February 18, 2021 09:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tlusser/c59b4feb280bfb9b0634b3ba7d9f0e2c to your computer and use it in GitHub Desktop.
Save tlusser/c59b4feb280bfb9b0634b3ba7d9f0e2c to your computer and use it in GitHub Desktop.
Nexus Repository Manager dependency/namespace confusion checker

Nexus Repository Manager dependency/namespace confusion Checker Task script

This repository contains a script to check if you have artifacts containing the same name between your repositories. This can be used to check if you're affected by a Dependency Confusion Attack

For example

npm-hosted has packages published with the @mycompany/artifact@2.0.1
npm-proxy has a package called @mycompany/artifact@10.0.1

This would be a match.

Requirements

  • NXRM3 OSS or PRO

Instructions

Step 1: Customise values in repo-diff.groovy

You'll need to modify the script to include

  1. Repositories to compare in repositories. e.g. to compare ruby and npm hosted to their proxies
def repositories = [:]
//repositories["hosted"] = "proxy"
repositories["ruby-hosted"] = "ruby-proxy"
repositories["npm-hosted"] = "npm-group-proxy"

Step 2: Create new Task in NXRM3 OSS or PRO

If your mail settings are configured correctly you should now receive an email if a possible dependency/namespace confusion occured.

import org.sonatype.nexus.repository.Repository
import org.sonatype.nexus.repository.storage.Asset
import org.sonatype.nexus.repository.storage.Component;
import org.sonatype.nexus.repository.storage.Query
import org.sonatype.nexus.repository.storage.StorageFacet
import groovy.json.JsonOutput
def repositories = [:]
//repositories["hosted"] = "proxy"
def getArtifacts(repo) {
StorageFacet storageFacet = repo.facet(StorageFacet)
def tx = storageFacet.txSupplier().get()
def components = []
try {
tx.begin()
Iterable<Component> assets = tx.findComponents(Query.builder().suffix('order by name, last_updated').build(), [repo])
assets.each { artifact ->
components << "${artifact.group()}:${artifact.name()}"
}
tx.commit()
} catch (Exception e) {
log.warn("Error: {}", e.toString())
tx.rollback()
} finally {
tx.close()
}
return components
}
repositories.each { hosted, proxy ->
def hostedRepo = repository.repositoryManager.browse().find { it.name == hosted }
def proxyRepo = repository.repositoryManager.browse().find { it.name == proxy }
log.info("Comparing '$hostedRepo.name' and '$proxyRepo.name'")
hostedList = getArtifacts(hostedRepo)
proxyList = getArtifacts(proxyRepo)
intersection = hostedList.intersect(proxyList)
if (intersection.size) {
log.warn("Possible Dependency Confusion Attack detected: {}", "'$hostedRepo.name','$proxyRepo.name' = '$intersection'")
throw new Exception("Possible Dependency Confusion detected: {}", "'$hostedRepo.name','$proxyRepo.name' = '$intersection'")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment