User credentials leaked to third-party service via HTTP redirect in scs-library-client
Description
github.com/sylabs/scs-library-client is the Go client for the Singularity Container Services (SCS) Container Library Service. When the scs-library-client is used to pull a container image, with authentication, the HTTP Authorization header sent by the client to the library service may be incorrectly leaked to an S3 backing storage provider. This occurs in a specific flow, where the library service redirects the client to a backing S3 storage server, to perform a multi-part concurrent download. Depending on site configuration, the S3 service may be provided by a third party. An attacker with access to the S3 service may be able to extract user credentials, allowing them to impersonate the user. The vulnerable multi-part concurrent download flow, with redirect to S3, is only used when communicating with a Singularity Enterprise 1.x installation, or third party server implementing this flow. Interaction with Singularity Enterprise 2.x, and Singularity Container Services (cloud.sylabs.io), does not trigger the vulnerable flow. We encourage all users to update. Users who interact with a Singularity Enterprise 1.x installation, using a 3rd party S3 storage service, are advised to revoke and recreate their authentication tokens within Singularity Enterprise. There is no workaround available at this time.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
scs-library-client leaks HTTP Authorization header to S3 storage during redirect, allowing credential theft; patched in 1.3.4 and 1.4.2.
Vulnerability
Overview
The scs-library-client, a Go client for the Singularity Container Services (SCS) Container Library Service, contains a vulnerability that can leak the HTTP Authorization header to an S3 backing storage provider [1][4]. This occurs during a specific multi-part concurrent download flow where the library service redirects the client to an S3 server. The Authorization header, which contains user credentials, is inadvertently forwarded to the S3 service [1].
Exploitation
Prerequisites
Exploitation requires that the client communicates with a Singularity Enterprise 1.x installation or a third-party server implementing the same redirect flow [4]. The S3 storage service may be operated by a third party, and an attacker with access to that S3 service can capture the leaked credentials [1][4]. No additional authentication is needed beyond the ability to observe or intercept the S3 traffic.
Impact
An attacker who obtains the leaked credentials can impersonate the affected user, gaining unauthorized access to the container library service and potentially other resources [1][4]. The vulnerability does not affect interactions with Singularity Enterprise 2.x or the cloud.sylabs.io service [4].
Mitigation
Patches are available in scs-library-client versions 1.3.4 and 1.4.2 [4]. Users are strongly encouraged to update and, if they interact with a Singularity Enterprise 1.x installation using a third-party S3 service, to revoke and recreate their authentication tokens within Singularity Enterprise [4]. No workaround exists for the vulnerable flow [4].
AI Insight generated on May 20, 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.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/sylabs/scs-library-clientGo | >= 1.4.0, < 1.4.2 | 1.4.2 |
github.com/sylabs/scs-library-clientGo | < 1.3.4 | 1.3.4 |
Affected products
4- ghsa-coords3 versionspkg:golang/github.com/sylabs/scs-library-clientpkg:rpm/opensuse/apptainer&distro=openSUSE%20Tumbleweedpkg:rpm/opensuse/singularity-ce&distro=openSUSE%20Tumbleweed
>= 1.4.0, < 1.4.2+ 2 more
- (no CPE)range: >= 1.4.0, < 1.4.2
- (no CPE)range: < 1.1.6-1.1
- (no CPE)range: < 4.1.3-1.1
- sylabs/scs-library-clientv5Range: < 1.34
Patches
3b5db2aacba6bMerge pull request from GHSA-7p8m-22h4-9pj7
1 file changed · +18 −3
client/pull.go+18 −3 modified@@ -236,13 +236,28 @@ func (c *Client) legacyDownloadImage(ctx context.Context, arch, name, tag string return err } + redirectURL, err := url.Parse(res.Header.Get("Location")) + if err != nil { + return err + } + var creds credentials - if c.AuthToken != "" { + if c.AuthToken != "" && samehost(c.BaseURL, redirectURL) { + // Only include credentials if redirected to same host as base URL creds = bearerTokenCredentials{authToken: c.AuthToken} } - // Use uri from Location header to download artifact - return c.multipartDownload(ctx, res.Header.Get("Location"), creds, dst, img.Size, spec, pb) + // Use redirect URL to download artifact + return c.multipartDownload(ctx, redirectURL.String(), creds, dst, img.Size, spec, pb) +} + +// samehost returns true if host1 and host2 are, in fact, the same host by +// comparing scheme (https == https) and host, including port. +// +// Hosts will be treated as dissimilar if one host includes domain suffix +// and the other does not, even if the host names match. +func samehost(host1, host2 *url.URL) bool { + return strings.EqualFold(host1.Scheme, host2.Scheme) && strings.EqualFold(host1.Host, host2.Host) } func parseContentLengthHeader(val string) (int64, error) {
eebd7caaab31fix: omit credentials for redirected URLs
1 file changed · +18 −3
client/pull.go+18 −3 modified@@ -236,13 +236,28 @@ func (c *Client) legacyDownloadImage(ctx context.Context, arch, name, tag string return err } + redirectURL, err := url.Parse(res.Header.Get("Location")) + if err != nil { + return err + } + var creds credentials - if c.AuthToken != "" { + if c.AuthToken != "" && samehost(c.BaseURL, redirectURL) { + // Only include credentials if redirected to same host as base URL creds = bearerTokenCredentials{authToken: c.AuthToken} } - // Use uri from Location header to download artifact - return c.multipartDownload(ctx, res.Header.Get("Location"), creds, dst, img.Size, spec, pb) + // Use redirect URL to download artifact + return c.multipartDownload(ctx, redirectURL.String(), creds, dst, img.Size, spec, pb) +} + +// samehost returns true if host1 and host2 are, in fact, the same host by +// comparing scheme (https == https) and host, including port. +// +// Hosts will be treated as dissimilar if one host includes domain suffix +// and the other does not, even if the host names match. +func samehost(host1, host2 *url.URL) bool { + return strings.EqualFold(host1.Scheme, host2.Scheme) && strings.EqualFold(host1.Host, host2.Host) } func parseContentLengthHeader(val string) (int64, error) {
68ac4cab5cdafix: remove extraneous Authorization HTTP header in range request #153
1 file changed · +5 −1
client/pull.go+5 −1 modified@@ -104,11 +104,15 @@ type Downloader struct { // httpGetRangeRequest performs HTTP GET range request to URL specified by 'u' in range start-end. func (c *Client) httpGetRangeRequest(ctx context.Context, url string, start, end int64) (*http.Response, error) { - req, err := c.newRequestWithURL(ctx, http.MethodGet, url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } + if v := c.UserAgent; v != "" { + req.Header.Set("User-Agent", v) + } + req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", start, end)) return c.HTTPClient.Do(req)
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-7p8m-22h4-9pj7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-23538ghsaADVISORY
- github.com/sylabs/scs-library-client/commit/68ac4cab5cda0afd8758ff5b5e2e57be6a22fcfaghsax_refsource_MISCWEB
- github.com/sylabs/scs-library-client/commit/b5db2aacba6bf1231f42dd475cc32e6355ab47b2ghsax_refsource_MISCWEB
- github.com/sylabs/scs-library-client/commit/eebd7caaab310b1fa803e55b8fc1acd9dcd2d00cghsax_refsource_MISCWEB
- github.com/sylabs/scs-library-client/security/advisories/GHSA-7p8m-22h4-9pj7ghsax_refsource_CONFIRMWEB
- pkg.go.dev/vuln/GO-2023-1497ghsaWEB
News mentions
0No linked articles in our index yet.