Metadata-Version: 2.4
Name: worthless
Version: 0.3.5
Summary: Split-key reverse proxy that makes leaked API keys worthless
Author: Shachar Mendelowitz
License: AGPL-3.0-only
Project-URL: Homepage, https://github.com/shacharm2/worthless
Project-URL: Repository, https://github.com/shacharm2/worthless
Project-URL: Issues, https://github.com/shacharm2/worthless/issues
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=46.0.5
Requires-Dist: aiosqlite>=0.22.1
Requires-Dist: httpx>=0.28
Requires-Dist: fastapi>=0.115
Requires-Dist: uvicorn[standard]>=0.34
Requires-Dist: typer>=0.15
Requires-Dist: python-dotenv>=1.0
Requires-Dist: psutil>=5.9
Requires-Dist: keyring>=25.0
Requires-Dist: tomli>=2.0; python_version < "3.11"
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == "mcp"
Provides-Extra: dev
Requires-Dist: deptry>=0.22; extra == "dev"
Requires-Dist: pre-commit>=4.0; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
Requires-Dist: pyright>=1.1; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Provides-Extra: test
Requires-Dist: anthropic>=0.40; extra == "test"
Requires-Dist: hypothesis>=6.0; extra == "test"
Requires-Dist: openai>=1.54; extra == "test"
Requires-Dist: pytest>=8.0; extra == "test"
Requires-Dist: pytest-asyncio>=0.24; extra == "test"
Requires-Dist: pytest-benchmark>=5.0; extra == "test"
Requires-Dist: pytest-console-scripts>=1.4; extra == "test"
Requires-Dist: pytest-cov>=7.0.0; extra == "test"
Requires-Dist: pytest-randomly>=3.16; extra == "test"
Requires-Dist: pytest-rerunfailures>=16.1; extra == "test"
Requires-Dist: pytest-timeout>=2.3; extra == "test"
Requires-Dist: pytest-xdist>=3.6; extra == "test"
Requires-Dist: respx>=0.22; extra == "test"
Requires-Dist: scipy>=1.12; extra == "test"
Requires-Dist: syrupy>=4.8; extra == "test"
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "test"
Provides-Extra: qa
Requires-Dist: bandit[sarif]>=1.8; extra == "qa"
Requires-Dist: mutmut>=3.0; extra == "qa"
Requires-Dist: pip-audit>=2.8; extra == "qa"
Requires-Dist: schemathesis>=4.0; python_version >= "3.11" and extra == "qa"
Requires-Dist: semgrep>=1.155.0; extra == "qa"
Provides-Extra: fuzz
Requires-Dist: atheris>=2.3; extra == "fuzz"
Dynamic: license-file

# Worthless

**Make leaked API keys worthless.**

[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org)
[![License: AGPL-3.0](https://img.shields.io/badge/license-AGPL--3.0-green)](LICENSE)
[![Tests](https://github.com/shacharm2/worthless/actions/workflows/tests.yml/badge.svg)](https://github.com/shacharm2/worthless/actions/workflows/tests.yml)

When your `.env` leaks, the keys inside are placeholders. The real key never sits in your repo, your shell history, or your laptop's memory.

## Quickstart

```bash
curl -sSL https://worthless.sh | sh        # fresh machine, no Python needed
# or, if you already have Python 3.10+:
pipx install worthless
```

Then `cd` into your project and run `worthless`. It detects keys in your `.env`, splits them, starts a local proxy. No code changes.

The Worker emits an `X-Worthless-Script-Sha256` header so you can [verify the bytes you ran match the bytes the Worker advertised](https://docs.wless.io/install-security/) before piping into `sh`. The check catches transit/cache tampering, not origin compromise — cosign-signed release manifests for that are tracked in [WOR-303](https://linear.app/plumbusai/issue/WOR-303).

Full install options (Docker, MCP for Claude Code / Cursor / Windsurf, GitHub Actions, the verified-install flow, kill-switch runbook): **[docs.wless.io](https://docs.wless.io)**

## Scope

Worthless scans for **LLM provider API key prefixes only** — currently
`openai` (`sk-`, `sk-proj-`), `anthropic` (`sk-ant-`), `google`
(`AIza`), and `xai` (`xai-`). For general secret detection (cloud
tokens, GitHub PATs, AWS access keys, npm tokens, Cloudflare API
tokens, etc.), use
[gitleaks](https://github.com/gitleaks/gitleaks) or
[trufflehog](https://github.com/trufflesecurity/trufflehog) as a
companion tool — worthless will not flag those and is not trying to
replace them.

## How it works

1. `worthless lock` splits each API key into two shards
2. Shard A stays on your machine (encrypted). Shard B goes to the proxy database
3. Your `.env` is rewritten with shard A — format-preserving, but cryptographically useless alone
4. The proxy reconstructs the key only when the rules engine approves the request
5. Spend cap blown? The key never forms. The request never reaches the provider

## Platforms

| Platform | Status |
|---|---|
| macOS | Supported |
| Linux | Supported |
| Windows + WSL | Supported |
| Native Windows | Not supported — use WSL or Docker |

Native-Windows support is tracked in [WOR-237](https://linear.app/plumbusai/issue/WOR-237). See [docs.wless.io](https://docs.wless.io) for the full distro support matrix.

## Versioning

PyPI version, signed git tag (`vX.Y.Z`), and the `X-Worthless-Script-Tag` header on `worthless.sh` are kept aligned — CI fails fast if `pyproject.toml` and the tag disagree. `install.sh` resolves the latest `worthless` from PyPI at install time; pin via `WORTHLESS_VERSION=x.y.z curl -sSL https://worthless.sh | sh`.

## Documentation

Everything lives at **[docs.wless.io](https://docs.wless.io)** — install guides, the security model, wire protocol, recovery runbook, the verified-install flow, and the agent skill file (Claude Code / Cursor / Windsurf).

## Development

```bash
git clone https://github.com/shacharm2/worthless && cd worthless
uv sync --extra dev --extra test
uv run pytest
```

Internal developer documentation lives in [`engineering/`](engineering/). Security invariants are in [`SECURITY.md`](SECURITY.md).

## Contributing

PRs welcome. Read [CONTRIBUTING-security.md](CONTRIBUTING-security.md) first.

## License

[AGPL-3.0](LICENSE)
