Skip to main content

taintrace

CI Python License PyPI Downloads Release Stars Docs

Typosquat detector for AI coding agent dependencies.

taintrace scans your lockfiles (Cargo.lock, package-lock.json, requirements.txt, go.sum) for package names that suspiciously resemble known legitimate packages — the exact vector used in the arrayref@0.3.10 attack (August 2026), where proc-macro1 imitated proc-macro2 to execute arbitrary code during cargo build.

Table of contents

The Problem

AI coding agents install dependencies automatically. Typosquats pass undetected by scanners like cargo audit or npm audit because they have no known CVE — they're brand new packages with malicious build.rs or proc-macros.

Traditional scanners check known-bad. taintrace checks suspicious-similar.

Install

pip install taintrace

Usage

Scan lockfiles

taintrace check Cargo.lock

Multiple lockfiles at once:

taintrace check Cargo.lock package-lock.json requirements.txt

Scan PHP/Composer lockfiles:

taintrace check composer.lock

Scan a lockfile

taintrace check Cargo.lock
╭──────────────────────────────────────────────╮
│ taintrace v0.2.1 — scanning Cargo.lock       │
│ Total deps: 42 | Suspects: 1                 │
╰──────────────────────────────────────────────╯

🚨 Typosquat Suspects
┏━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Package     ┃ Risk     ┃ Score ┃ Similar To     ┃ Reason                  ┃
┣━━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ proc-macro1 ┃ CRITICAL ┃ 0.980 ┃ proc-macro2    ┃ Near-identical to...    ┃
┗━━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━┛

❌ 1 suspect(s) found — review required

Scan directory tree

taintrace scan-directory .                # recursive scan of all lockfiles
taintrace scan-directory /path/to/repo    # scan specific path
taintrace scan-directory . --format sarif # SARIF output for CI/CD

Auto-discovers: Cargo.lock, package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lock, bun.lockb, requirements.txt, Pipfile.lock, poetry.lock, uv.lock, go.sum, Gemfile.lock, composer.json, composer.lock, Package.resolved, Package.swift, mix.lock, build.gradle, build.gradle.kts, gradle/libs.versions.toml.

JSON output (CI/CD)

taintrace check Cargo.lock --format json

SARIF output (GitHub Code Scanning)

taintrace check Cargo.lock --format sarif > results.sarif

Score a single package

taintrace score proc-macro1

Exit codes

  • 0 — no suspects found
  • 1 — one or more suspects detected (use in CI/CD gates)

Configuration

taintrace automatically discovers and loads configuration files from the current working directory, parent directories, or your user home directory:

  • .taintrace.toml / taintrace.toml
  • .taintrace.yaml / .taintrace.yml / taintrace.yaml / taintrace.yml
  • pyproject.toml (under [tool.taintrace])
  • .taintracerc
  • ~/.config/taintrace/config.toml (or .yaml)

You can also explicitly pass a configuration file path using the -c / --config flag:

taintrace check Cargo.lock --config /path/to/my-config.yaml

Example .taintrace.toml

[taintrace]
threshold = 0.85
format = "text"
no_informational = true
ignore = [
  "my-internal-mirror",
  "legit-package-with-similar-name"
]

Example .taintrace.yaml

taintrace:
  threshold: 0.85
  output_format: sarif
  no_informational: false
  ignore:
    - my-internal-mirror
    - ${CUSTOM_IGNORE_PKG}

Example pyproject.toml

[tool.taintrace]
threshold = 0.80
ignore = ["my-corp-pkg"]

Environment Variable Interpolation

Configuration values support environment variable interpolation using $VAR or ${VAR} syntax (e.g. ${CI_PROJECT_NAME} or $SCAN_THRESHOLD).

Ignoring False Positives

To suppress specific known-safe packages via the CLI directly:

taintrace check Cargo.lock --ignore proc-macro1 --ignore some-legit-package

Ignored packages are excluded from CLI, JSON, and SARIF output. CLI flags override options defined in configuration files.

Algorithms

  • Levenshtein distance — edit distance between names
  • Soundex phonetic — catches homophones ("night" vs "nite")
  • Substring matching — detects containment ("lodash" vs "lodash1")
  • Combined scoring — weighted combination of all signals

Use --threshold with check or scan-directory to set the minimum similarity considered during matching. The default is 0.7; higher values require closer package-name matches. Reports include each matched package with its similarity score.

Multi-ecosystem

Ecosystem Lockfiles Status
Rust Cargo.lock, Cargo.toml ✅
Node.js package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lock, bun.lockb ✅
Python requirements.txt, poetry.lock, pyproject.toml (PEP 621 + Poetry), uv.lock, Pipfile.lock ✅
Go go.sum ✅
Ruby Gemfile.lock ✅
PHP composer.json, composer.lock ✅
Swift Package.resolved, Package.swift ✅
Elixir mix.lock ✅
Gradle build.gradle, build.gradle.kts, gradle/libs.versions.toml ✅

Known-package data

Similarity suggestions come from a built-in, offline package database. Each ecosystem is backed by real registry data, not hand-written guesses:

Ecosystem Source
Rust, Node.js, Python, Go, Ruby, PHP, Swift, Elixir curated lists in taintrace/db.py
Java / Maven src/taintrace/data/java_packages.txt — 7,848 groupId:artifactId coordinates generated from the Maven Central repository index, with provenance recorded in the file header

Refresh the Java data against Maven Central with:

python scripts/generate_java_packages.py           # regenerate
python scripts/generate_java_packages.py --check   # validate the committed file (offline)
python scripts/generate_java_packages.py --verify  # re-query Maven Central and diff

Java coordinates are matched in their groupId:artifactId form, the same shape the Gradle parsers emit; a bare artifactId is also accepted. If you request an ecosystem that has no data at all, taintrace says so explicitly instead of reporting "no similar packages found".

CI/CD integration

GitHub Action

- uses: yunaremaia/taintrace@main
  with:
    lockfile: Cargo.lock
    format: sarif
    sarif-output: taintrace.sarif
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: taintrace.sarif

Auto-detect lockfiles in your repo root:

- uses: yunaremaia/taintrace@main
  with:
    format: cli

Pre-commit hook

repos:
  - repo: https://github.com/yunaremaia/taintrace
    rev: v0.2.1
    hooks:
      - id: taintrace

Why taintrace?

  • AI-agent-aware — built for the vector AI agents expose (automatic dep installation)
  • Zero config — just point at your lockfile
  • Offline-first — no API calls, no data leaves your machine
  • SARIF-native — integrates with GitHub Code Scanning
  • Open source — MIT licensed, no paywall

How it differs

Tool CVE-based Typosquat AI-aware Open source
cargo-audit ✅ ❌ ❌ ✅
npm audit ✅ ❌ ❌ ✅
Socket ✅ Partial ❌ ❌
Phylum ✅ Partial ❌ ❌
taintrace ❌ ✅ ✅ ✅

If this tool is useful to you, a star helps other people find it.

  • driftcheck — detect version drift between docs and toolchain files
  • depscan — scan dependencies across multiple ecosystems
  • agentcost — track and attribute LLM spend per agent
  • vibeguard — guardrails for AI-generated code changes

Part of a family of focused, single-purpose developer tools — each one does one thing and does it well.

License

MIT — see LICENSE

Metadata

Release files for taintrace 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for taintrace 0.2.3
File Size Uploaded
taintrace-0.2.3.tar.gz 126.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for taintrace 0.2.3
File Interpreter ABI Platform
taintrace-0.2.3-py3-none-any.whl Python 3 none any Details

Total release size: 201.0 kB

Release files / taintrace-0.2.3.tar.gz

Download URL taintrace-0.2.3.tar.gz
Size 126.3 kB
Tags Source
SHA-256 checksum
How to use checksums
05c1eb232057de9e6118067cc495d4bdb1d541f832342db595531505c7f9c931
BLAKE2b-256 checksum
How to use checksums
f5a46bd631116f2dcdbe0dfc06f2d552ef879a3e94baf773780c49d7203b2c03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / taintrace-0.2.3-py3-none-any.whl

Download URL taintrace-0.2.3-py3-none-any.whl
Size 74.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6b8d7673181f149a337df14fb2f1d9195dfc99c664c65913138a327f7efd0a34
BLAKE2b-256 checksum
How to use checksums
d0791dfca5ab87df284d366be40189f4918ad6f5dce713a75e3db2929f05276c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

This release

0.2.3 This release

2 release files

0.2.2

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page