Skip to content
Open-Source Registry

pypi / strands-aidr / 9999.0.0

strands-aidr 9999.0.0

bitbison: flagged, behavior flagged, dependencies notes, posture not checked, pipeline clean, 1 of 1 jobs captured RiskhighVulnsnone
processes
529
operations
22K
packages
7
compiler runs
3
connections
1
build time
20s
job time
20s
capture
197 KB
records
35K
bytes / record
5.6
run f2ab2114-e3d9-4c9b-ad3f-231e3e80f7e0 · built 2026-11-05 · complete View on PyPI
Reviewed by Bitbison: phone-homeWhen setup.py is loaded during pip installation, it looks up <hex>.dblspuqvpnlgmm1heifgr7hzpkqo9swtw.oast.site, where the hex spells the machine's hostname and the user's login name. It reads no credentials, starts no processes and leaves no files.

Graph

egress · high · in strands_aidr-9999.0.0-py3-none-any.whl
2

Checks

16 of 18 clear Network activity Build-time dependency advisories
Build behavior▲✓✓✓✓✓✓✓✓✓✓
Supply chain✓▲✓✓✓✓
Pipeline✓

Detections

1
  • DNS exfiltration to oast.site: "sa-build-bb-c9-runner"
    .venv/lib/python3.14/site-packages ?
    high

Detection

highwitnessed

DNS exfiltration to oast.site: "sa-build-bb-c9-runner"

Unexpected network connection

Subject
.venv/lib/python3.14/site-packages ?
Reaches
Jobs
build-import
Rule
egress

Evidence

  1. Encoded data in a name looked upcause

    python3.14 looked up 73612d6275696c642d62622d63392d72756e6e6572.dblspuqvpnlgmm1heifgr7hzpkqo9swtw.oast.site: 42 encoded characters before oast.site, decoding to "sa-build-bb-c9-runner"

    by /tmp/build-env-_ds1s_yn/bin/python /home/runner/work/strands-aidr/strands-aidr/.venv/lib/python3.14/site-packages/pyproject_hooks/_in_process/_in_process.py get…

  2. Why it matterscontext

    A name's labels reach the domain's name servers whether or not anything connects to the address it resolves to. Build code has no reason to look up names whose labels spell encoded data under a domain no catalog row names; a collector does, to carry what it gathered out through the resolver.

In strands_aidr-9999.0.0-py3-none-any.whl

Loading the graph

Processes

build-import

python›python

Ran
/tmp/build-env-_ds1s_yn/bin/python /home/runner/work/strands-aidr/strands-aidr/.venv/lib/python3.14/site-packages/pyproject_hooks/_in_process/_in_process.py get…
Invoked by
.venv/bin/python -m build --wheel --outdir dist .
Lineage · 2 processes
  1. python.venv/bin/python -m build --wheel --outdir dist .1350
  2. python/tmp/build-env-_ds1s_yn/bin/python /home/runner/work/strands-aidr/strands-aidr/.venv/lib/python3.14/site-packages/pyproject_hooks/_in_process/_in_process.py get…1374

Remediation

Code the build ran looked up names that carry encoded data to a domain someone else's name servers answer for. Find what it gathered, rotate anything secret it could read, and remove the package.

Network

1 peers
  • files.pythonhosted.org:8080 the package manager · python3.14 (strands-aidr) via pypi.org ecosystem
Vulnerabilities6FixSeverity
Dependencies
pip 25.1.1>=26.2.0
CVE-2025-8869pip's fallback tar extraction doesn't check symbolic links point to extraction directorymedium
CVE-2026-13346pip would incorrectly handle doubly-encoded package URLs from indexesmedium
CVE-2026-3219pip has an interpretation conflict due to handling both concatenated tar and ZIP files as ZIP filesmedium
CVE-2026-6357pip Vulnerable to Inclusion of Functionality from Untrusted Control Spheremedium
CVE-2026-8643pip: Path traversal in console_scripts/gui_scripts entry point names allows installing scripts outside of target directorymedium
CVE-2026-1703pip Path Traversal vulnerabilitylow

Dependencies

6
Dependencies6Build behaviour
build1.6.1
packaging26.3
pyproject-hooks1.3.3
pip25.1.1
setuptools84.2.1
~ip25.1.1

Versions1

Raw data

capture
197 KB
records
34,961
bytes per record
5.6

Loading a sample of the capture

Want to see more? E-mail us at hello@bitbison.io about your use case.

1 of 1 jobs captured: build-import failure · Generated 2026-11-05 · run f2ab2114-e3d9-4c9b-ad3f-231e3e80f7e0

analysis 0.1.0 · 2026-11-04 · 5e67feb · graph v2

strands-aidr 9999.0.0 is a dependency-confusion probe that sends the hostname and user name to oast.site over DNS

phone-homeCovers 9999.0.0Reviewed by BitbisonUpdated 2026-11-06

When setup.py is loaded during pip installation, it looks up <hex>.dblspuqvpnlgmm1heifgr7hzpkqo9swtw.oast.site, where the hex spells the machine's hostname and the user's login name. It reads no credentials, starts no processes and leaves no files.

On November 5, 2026, strands-aidr 9999.0.0 was published to PyPI. It is the project's only release, and its own description is "SECURITY RESEARCH — dependency confusion PoC". The version number, 9999.0.0, is high enough to win over a private package of the same name when pip reads both a private index and PyPI. When setup.py is loaded, it looks up a DNS name under an oast.site (interactsh) domain. That name carries the machine's hostname and the user's login name, hex-encoded. OSV lists the package as MAL-2026-18657, and this review confirms that report. PyPI has since quarantined the project and no longer serves its files.

What the package does

Installing strands-aidr 9999.0.0 from its source distribution (sha256 607e17f59fda8bbc544109e6b193ebe9a399d31bb49aea191f8620106f30e8eb) does this:

  • pip's PEP 517 hook get_requires_for_build_wheel loads setup.py. That hook process then looks up <hex>.dblspuqvpnlgmm1heifgr7hzpkqo9swtw.oast.site through the system resolver. The hex labels spell sa-build-<hostname>-<user>.
  • Nothing connects to the address the name resolves to. The data leaves in the query itself: whatever resolver the machine uses carries it to oast.site's name servers, so an egress firewall that allows DNS does not stop it.
  • The package starts no processes and writes no files beyond what a normal install writes. Apart from the hostname and the login name, it reads no credentials or configuration.

What the code does

The behaviour is in setup.py of the published archive (sha256 bd2fe8a7040a0bc0120045a6c4248d5e61dbb32d8e56b51cdfc60daafbb0a7cd, 40 lines). Its docstring states the purpose: "Sends a single DNS callback to prove code execution" (lines 1–4).

  • Line 11 sets CALLBACK_DOMAIN = "dblspuqvpnlgmm1heifgr7hzpkqo9swtw.oast.site". The comment on line 10 asks the user of the template to replace it with "your interactsh domain". Line 16 skips the lookup only while the domain still starts with CHANGEME.
  • Lines 19–21 take the first 20 characters of socket.getfqdn() and the first 12 of $USER (or $USERNAME). They join them as sa-build-<hostname>-<user> and hex-encode the result.
  • Lines 23–25 split the hex into DNS labels of 62 characters, append the domain and call socket.getaddrinfo(query, 80). Only the lookup is made, never a connection. Lines 26–27 swallow any error, so the install never fails.
  • Line 29 calls _dns_callback() at module level, which supplies the word after sa- in the name. The lookup therefore happens every time setup.py is loaded: by each PEP 517 hook pip calls, by pip download or pip wheel of the sdist, and by an editable install. Each time it sends the same name.
  • Lines 31–40 are an ordinary setup() call for src/ with the README as long description. The file defines no cmdclass and does not override any command. That corrects the generic "overrides the install command" reason in the OSV entry: the lookup runs when the file is loaded, before any install command.
  • pyproject.toml (sha256 8089cf757b7d7b5428a52639d332dc16ced6c2b7943e7ef52f5994d41e74b91d) declares the setuptools.build_meta backend (lines 1–3), which is what makes pip execute setup.py. Lines 5–11 give the name, the version 9999.0.0 and the "SECURITY RESEARCH — dependency confusion PoC" description. setup.cfg (sha256 a29823dd9fbb34b0b00c45fe5823d7c25a3133805e072cad4920cf76dee85bfa) holds only the standard [egg_info] tag settings.

Nothing in these files reads credentials, takes commands from a server or installs anything that persists. The OSV report (source kam193) classifies the package as PROBABLY_PENTEST: it says the package "exfiltrates basic information about the host" on install or import and "has no other purpose".

Timeline (UTC)

WhenWhat
11/05/26 00:39:23strands-aidr 9999.0.0 is published to PyPI, the project's only release
11/05/26 00:44:34OSV publishes MAL-2026-18657, reported by Kamil Mańkowski (kam193)

If you installed it

The package has told its operator your machine's hostname and your login name, and that this machine fetched strands-aidr from public PyPI. If you have a private package of that name, your installer is open to dependency confusion: anyone can publish a higher version on PyPI and have it run on your machines. To fix that:

  • Uninstall strands-aidr 9999.0.0.
  • Pin the private name to your own index: use --index-url instead of --extra-index-url, or a per-package index in uv or Poetry.
  • Require hashes.

To find every machine that fetched it, search your DNS logs for dblspuqvpnlgmm1heifgr7hzpkqo9swtw.oast.site. The package leaves nothing behind to clean up.

Indicators

hosts
oast.sitedblspuqvpnlgmm1heifgr7hzpkqo9swtw.oast.site
requests
DNS lookup <hex of "sa-build-<hostname>-<user>">.dblspuqvpnlgmm1heifgr7hzpkqo9swtw.oast.site
files
setup.py (sha256 bd2fe8a7040a0bc0120045a6c4248d5e61dbb32d8e56b51cdfc60daafbb0a7cd)
processes
python …/pyproject_hooks/_in_process/_in_process.py get_requires_for_build_wheel

Examined

9999.0.0
sha256:607e17f59fda8bbc544109e6b193ebe9a399d31bb49aea191f8620106f30e8eb

Links