VYPR
Moderate severityNVD Advisory· Published May 28, 2021· Updated Aug 3, 2024

Action Commands (run/shell/exec) Against Library URIs Ignore Configured Remote Endpoint

CVE-2021-32635

Description

Singularity is an open source container platform. In verions 3.7.2 and 3.7.3, Dde to incorrect use of a default URL, singularity action commands (run/shell/exec) specifying a container using a library:// URI will always attempt to retrieve the container from the default remote endpoint (cloud.sylabs.io) rather than the configured remote endpoint. An attacker may be able to push a malicious container to the default remote endpoint with a URI that is identical to the URI used by a victim with a non-default remote endpoint, thus executing the malicious container. Only action commands (run/shell/exec) against library:// URIs are affected. Other commands such as pull / push respect the configured remote endpoint. The vulnerability is patched in Singularity version 3.7.4. Two possible workarounds exist: Users can only interact with the default remote endpoint, or an installation can have an execution control list configured to restrict execution to containers signed with specific secure keys.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Singularity 3.7.2-3.7.3 ignores configured remote endpoint for library:// URIs, allowing a malicious container from the default endpoint to be executed.

Vulnerability

In Singularity versions 3.7.2 and 3.7.3, action commands (run, shell, exec) that specify a container using a library:// URI always retrieve the container from the default remote endpoint (cloud.sylabs.io) instead of the user-configured remote endpoint [1][4]. This flaw is due to incorrect use of a default URL in the handleLibrary function, which directly used endpoint.SCSDefaultLibraryURI rather than the current remote configuration [3]. Only run/shell/exec commands against library:// URIs are affected; pull and push commands correctly respect the configured endpoint [1].

Exploitation

An attacker can push a malicious container to the default remote endpoint (cloud.sylabs.io) with a library:// URI identical to one that a victim expects to pull from their non-default, configured remote endpoint [1][4]. When the victim runs singularity run library://attacker/container:tag, the action command ignores the configured endpoint and fetches the attacker's container from the default endpoint instead [1]. No additional authentication or user interaction beyond the victim executing the action command is required [1].

Impact

Successful exploitation allows the attacker to execute an arbitrary malicious container on the victim's system [1]. Depending on the container's content, this can lead to arbitrary code execution, data exfiltration, privilege escalation, or other compromise of the host system [1][4]. The victim runs the container with their own privileges, so the attacker's code inherits the victim's user permissions [2].

Mitigation

The vulnerability is patched in Singularity version 3.7.4, released on 2021-05-28 [1][4]. Users should upgrade to 3.7.4 or later. Two workarounds exist for users who cannot upgrade immediately: they can limit interaction to only the default remote endpoint, or they can configure an execution control list (ECL) to restrict execution to containers signed with specific secure keys [1]. The vulnerability is not currently listed on the CISA Known Exploited Vulnerabilities (KEV) catalog.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/sylabs/singularityGo
>= 3.7.2, < 3.7.43.7.4

Affected products

3

Patches

1
d52ae9d13979

Merge pull request from GHSA-5mv9-q7fq-9394

https://github.com/sylabs/singularityAdam HughesMay 26, 2021via ghsa
3 files changed · +71 2
  • cmd/internal/cli/actions.go+2 2 modified
    @@ -21,7 +21,6 @@ import (
     	"github.com/sylabs/singularity/internal/pkg/client/oci"
     	"github.com/sylabs/singularity/internal/pkg/client/oras"
     	"github.com/sylabs/singularity/internal/pkg/client/shub"
    -	"github.com/sylabs/singularity/internal/pkg/remote/endpoint"
     	"github.com/sylabs/singularity/internal/pkg/util/uri"
     	"github.com/sylabs/singularity/pkg/sylog"
     )
    @@ -75,7 +74,8 @@ func handleOras(ctx context.Context, imgCache *cache.Handle, cmd *cobra.Command,
     }
     
     func handleLibrary(ctx context.Context, imgCache *cache.Handle, pullFrom string) (string, error) {
    -	c, err := getLibraryClientConfig(endpoint.SCSDefaultLibraryURI)
    +	// Pass uri="" to use current remote
    +	c, err := getLibraryClientConfig("")
     	if err != nil {
     		return "", err
     	}
    
  • e2e/actions/actions.go+3 0 modified
    @@ -2198,6 +2198,8 @@ func E2ETests(env e2e.TestEnv) testhelper.Tests {
     		env: env,
     	}
     
    +	np := testhelper.NoParallel
    +
     	return testhelper.Tests{
     		"action URI":            c.RunFromURI,          // action_URI
     		"exec":                  c.actionExec,          // singularity exec
    @@ -2230,5 +2232,6 @@ func E2ETests(env e2e.TestEnv) testhelper.Tests {
     		"bind image":            c.bindImage,           // test bind image
     		"umask":                 c.actionUmask,         // test umask propagation
     		"no-mount":              c.actionNoMount,       // test --no-mount
    +		"invalidRemote":         np(c.invalidRemote),   // GHSA-5mv9-q7fq-9394
     	}
     }
    
  • e2e/actions/regressions.go+66 0 modified
    @@ -616,3 +616,69 @@ func (c actionTests) issue5690(t *testing.T) {
     		e2e.ExpectExit(0),
     	)
     }
    +
    +// If an invalid remote is set, we should not pull a container from the default
    +// library.
    +// GHSA-5mv9-q7fq-9394
    +func (c actionTests) invalidRemote(t *testing.T) {
    +	testEndpoint := "invalid"
    +	testEndpointURI := "https://cloud.example.com"
    +	testImage := "library://alpine"
    +
    +	// Exec library image from the default remote... ensure it succeeds
    +	argv := []string{testImage, "/bin/true"}
    +	c.env.RunSingularity(
    +		t,
    +		e2e.AsSubtest("exec default"),
    +		e2e.WithProfile(e2e.UserProfile),
    +		e2e.WithCommand("exec"),
    +		e2e.WithArgs(argv...),
    +		e2e.ExpectExit(0),
    +	)
    +
    +	// Add another endpoint
    +	argv = []string{"add", "--no-login", testEndpoint, testEndpointURI}
    +	c.env.RunSingularity(
    +		t,
    +		e2e.AsSubtest("remote add"),
    +		e2e.WithProfile(e2e.UserProfile),
    +		e2e.WithCommand("remote"),
    +		e2e.WithArgs(argv...),
    +		e2e.ExpectExit(0),
    +	)
    +	// Remove test remote when we are done here
    +	defer func(t *testing.T) {
    +		argv := []string{"remove", testEndpoint}
    +		c.env.RunSingularity(
    +			t,
    +			e2e.AsSubtest("remote remove"),
    +			e2e.WithProfile(e2e.UserProfile),
    +			e2e.WithCommand("remote"),
    +			e2e.WithArgs(argv...),
    +			e2e.ExpectExit(0),
    +		)
    +	}(t)
    +
    +	// Set as default
    +	argv = []string{"use", testEndpoint}
    +	c.env.RunSingularity(
    +		t,
    +		e2e.AsSubtest("remote use"),
    +		e2e.WithProfile(e2e.UserProfile),
    +		e2e.WithCommand("remote"),
    +		e2e.WithArgs(argv...),
    +		e2e.ExpectExit(0),
    +	)
    +
    +	// Exec library image from the invalid remote, should fail
    +	argv = []string{testImage, "/bin/true"}
    +	c.env.RunSingularity(
    +		t,
    +		e2e.AsSubtest("exec invalid"),
    +		e2e.WithProfile(e2e.UserProfile),
    +		e2e.WithCommand("exec"),
    +		e2e.WithArgs(argv...),
    +		e2e.ExpectExit(255),
    +	)
    +
    +}
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.