Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/smoke-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,73 @@ jobs:
name: smoke-html-${{ matrix.os }}
path: ${{ runner.temp }}/*.html
retention-days: 3

verify-aliases:
name: Verify alias packages on npm
runs-on: ubuntu-latest
if: >
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'

steps:
- uses: actions/checkout@v6

- uses: actions/setup-node@v6
with:
node-version: "20"
registry-url: "https://registry.npmjs.org"

- name: Resolve version
run: |
if [ -n "${{ github.event.inputs.version }}" ]; then
echo "VERSION=${{ github.event.inputs.version }}" >> "$GITHUB_ENV"
else
echo "VERSION=$(node -p "require('./package.json').version")" >> "$GITHUB_ENV"
fi

- name: Wait for all alias packages on npm
run: |
ALIASES=(
failproof
failproof-ai
fail-proof-ai
failproof_ai
fail_proof_ai
fail-proofai
failprof
failprof-ai
failprofai
fail-prof-ai
failprof_ai
faliproof
faliproof-ai
faliproofai
)
DELAYS=(0 5 10 20 40 80)
FAILED=()

for ALIAS in "${ALIASES[@]}"; do
PUBLISHED=""
for delay in "${DELAYS[@]}"; do
if [ "$delay" -gt 0 ]; then
echo "[$ALIAS] Waiting ${delay}s before retry..."
sleep "$delay"
fi
PUBLISHED=$(npm view "${ALIAS}@${VERSION}" version 2>/dev/null || true)
if [ "$PUBLISHED" = "$VERSION" ]; then
echo "[$ALIAS] OK — ${VERSION}"
break
fi
echo "[$ALIAS] Not yet available (attempt after ${delay}s)"
done
if [ "$PUBLISHED" != "$VERSION" ]; then
echo "::error::[$ALIAS] version ${VERSION} never appeared on npm after all retries"
FAILED+=("$ALIAS")
fi
done

if [ "${#FAILED[@]}" -gt 0 ]; then
echo "::error::Failed aliases: ${FAILED[*]}"
exit 1
fi
echo "All ${#ALIASES[@]} alias packages verified at version ${VERSION}"
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Open-source hooks, policies, and session visualization for **Claude Code** and t
| [Dashboard](./dashboard.md) | Session viewer, policy management, and activity log |
| [Architecture](./architecture.md) | How the hook handler, config loading, and policy evaluation work |
| [Testing](./testing.md) | Unit tests, E2E tests, and test helpers |
| [Package Aliases](./package-aliases.md) | Registered typosquat-prevention aliases and how they work |

---

Expand Down
74 changes: 74 additions & 0 deletions docs/package-aliases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Package Aliases & Typosquatting Protection

## Official package

The canonical npm package is **`failproofai`**:

```bash
npm install -g failproofai
```

---

## Why we own the alias names

Typosquatting is a common supply-chain attack where a malicious actor registers a package name that is one keystroke away from a popular package. Unsuspecting users who mistype the install command end up running attacker-controlled code with full system access — exactly the kind of threat Failproof AI is designed to defend against.

To eliminate this surface, **we pre-emptively own all common misspellings and formatting variants** of `failproofai` on npm. None of these names can be registered by a third party. Each one is a thin proxy that installs and delegates to the real `failproofai` package.

---

## Registered aliases

**Formatting variants** — different ways to write "failproof ai":

| Package | Install command |
|---------|----------------|
| `failproof` | `npm install -g failproof` |
| `failproof-ai` | `npm install -g failproof-ai` |
| `fail-proof-ai` | `npm install -g fail-proof-ai` |
| `failproof_ai` | `npm install -g failproof_ai` |
| `fail_proof_ai` | `npm install -g fail_proof_ai` |
| `fail-proofai` | `npm install -g fail-proofai` |

**`failprof*` typos** — missing one `o` from "proof":

| Package | Install command |
|---------|----------------|
| `failprof` | `npm install -g failprof` |
| `failprof-ai` | `npm install -g failprof-ai` |
| `failprofai` | `npm install -g failprofai` |
| `fail-prof-ai` | `npm install -g fail-prof-ai` |
| `failprof_ai` | `npm install -g failprof_ai` |

**`faliproof*` typos** — transposed `a` and `i`:

| Package | Install command |
|---------|----------------|
| `faliproof` | `npm install -g faliproof` |
| `faliproof-ai` | `npm install -g faliproof-ai` |
| `faliproofai` | `npm install -g faliproofai` |

All 14 aliases are published by **ExosphereHost Inc.** (the same npm account as `failproofai`). You can verify any of them:

```bash
npm info failproof-ai
# Look for: "ExosphereHost Inc." in the maintainers field
```

---

## How the aliases work

Each alias package:

1. Lists `failproofai` as a dependency — so the real package (including its `postinstall` hook setup) runs on install
2. Exposes a binary matching its own name (e.g. `failproof-ai`) that proxies all arguments to the `failproofai` binary

The proxy is a two-line Node script; there is no logic, no network calls, and no data collection beyond what `failproofai` itself does.

---

## If you find a name we missed

Open an issue at [exospherehost/failproofai](https://github.com/exospherehost/failproofai/issues) and we will register it.